nodus-wechat 0.7.1 → 0.7.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/README.md CHANGED
@@ -19,6 +19,7 @@ npx nodus-wechat doctor
19
19
  npx nodus-wechat start
20
20
  npx nodus-wechat start --no-install
21
21
  npx nodus-wechat start --no-hermes
22
+ npx nodus-wechat start --no-dashboard
22
23
  npx nodus-wechat start --docker
23
24
  npx nodus-wechat status
24
25
  npx nodus-wechat logs
@@ -50,11 +51,13 @@ the official OpeniLink installer.
50
51
  - Installs the OpeniLink + webhook POC runtime at `~/.nodus-wechat/runtime`.
51
52
  - Writes Hermes common settings to `~/.hermes/config.yaml`.
52
53
  - Writes the AstraGate key to `~/.hermes/.env` as `ASTRAGATE_API_KEY`.
54
+ - Sets Hermes static UI/message language to Simplified Chinese with `display.language: zh`.
53
55
  - Writes runtime `.env`, Docker Compose, webhook server, helper scripts, and the OpeniLink reply plugin.
54
56
  - Stores gateway base URL, api key, model, Hermes paths, OpeniLink origin, webhook port, and runtime path.
55
57
  - Checks Node.js, local configuration, Hermes files, runtime files, Python, OpeniLink CLI, optional Docker Compose availability, Hermes CLI availability, and WeChat app detection with `doctor`.
56
- - Starts/stops Hermes Gateway, OpeniLink, and the local webhook with native host processes by default.
58
+ - Starts/stops Hermes Gateway, Hermes Dashboard, OpeniLink, and the local webhook with native host processes by default.
57
59
  - Installs Hermes and OpeniLink automatically during `start` when the native CLIs are missing.
60
+ - Exposes the Hermes management/configuration UI at `http://127.0.0.1:9119`.
58
61
  - Keeps Docker Compose available only when `--docker` is passed.
59
62
  - Removes Nodus WeChat config/runtime files with `uninstall --yes`.
60
63
  - Cleans Nodus WeChat config/runtime plus generated Hermes settings with `clean --yes`.
@@ -15,6 +15,7 @@ const DEFAULT_OPENILINK_ORIGIN = "http://localhost:9800";
15
15
  const DEFAULT_OPENILINK_RP_ID = "localhost";
16
16
  const DEFAULT_OPENILINK_PORT = 9800;
17
17
  const DEFAULT_WEBHOOK_PORT = 9811;
18
+ const DEFAULT_HERMES_DASHBOARD_PORT = 9119;
18
19
  const TEMPLATE_DIR = path.join(__dirname, "..", "templates", "wechat-agent-poc");
19
20
 
20
21
  function configHome() {
@@ -43,7 +44,7 @@ Usage:
43
44
  nodus-wechat install-hermes
44
45
  nodus-wechat install-openilink
45
46
  nodus-wechat doctor
46
- nodus-wechat start [--docker] [--no-install] [--no-hermes]
47
+ nodus-wechat start [--docker] [--no-install] [--no-hermes] [--no-dashboard]
47
48
  nodus-wechat status [--docker]
48
49
  nodus-wechat logs [--docker]
49
50
  nodus-wechat stop [--docker]
@@ -56,7 +57,7 @@ Commands:
56
57
  install-openilink
57
58
  Install OpeniLink Hub native CLI with the official installer.
58
59
  doctor Check local prerequisites and configuration.
59
- start Start Hermes Gateway, OpeniLink, and webhook on the host by default.
60
+ start Start Hermes Gateway, Hermes Dashboard, OpeniLink, and webhook on the host by default.
60
61
  status Show local process status.
61
62
  logs Follow local runtime logs.
62
63
  stop Stop the local runtime.
@@ -78,7 +79,7 @@ function parseArgs(argv) {
78
79
  }
79
80
 
80
81
  const key = item.slice(2);
81
- if (key === "help" || key === "yes" || key === "install-hermes" || key === "docker" || key === "no-install" || key === "no-hermes") {
82
+ if (key === "help" || key === "yes" || key === "install-hermes" || key === "docker" || key === "no-install" || key === "no-hermes" || key === "no-dashboard") {
82
83
  result[key] = true;
83
84
  continue;
84
85
  }
@@ -198,6 +199,7 @@ function buildHermesConfig(config) {
198
199
  ' - "all"',
199
200
  "display:",
200
201
  ' tool_progress: "all"',
202
+ ' language: "zh"',
201
203
  "compression:",
202
204
  " enabled: true",
203
205
  "",
@@ -532,12 +534,14 @@ function commandPath(name) {
532
534
  }
533
535
 
534
536
  function hermesPath(config) {
537
+ const configuredHome = config?.hermes?.home || hermesHome();
538
+ const configuredVenvHermes = path.join(configuredHome, "hermes-agent", "venv", "bin", "hermes");
539
+ const defaultUserHermes = path.join(os.homedir(), ".local", "bin", "hermes");
540
+ const defaultHermesHome = path.join(os.homedir(), ".hermes");
535
541
  return (
536
542
  commandPath("hermes") ||
537
- (fs.existsSync(path.join(os.homedir(), ".local", "bin", "hermes")) ? path.join(os.homedir(), ".local", "bin", "hermes") : null) ||
538
- (config?.hermes?.home && fs.existsSync(path.join(config.hermes.home, "hermes-agent", "venv", "bin", "hermes"))
539
- ? path.join(config.hermes.home, "hermes-agent", "venv", "bin", "hermes")
540
- : null)
543
+ (fs.existsSync(configuredVenvHermes) ? configuredVenvHermes : null) ||
544
+ (configuredHome === defaultHermesHome && fs.existsSync(defaultUserHermes) ? defaultUserHermes : null)
541
545
  );
542
546
  }
543
547
 
@@ -553,6 +557,17 @@ function logPath(config, name) {
553
557
  return runtimePath(config, `${name}.log`);
554
558
  }
555
559
 
560
+ function localProcessNames(options = {}) {
561
+ const names = ["hermes", "hermes-dashboard", "openilink", "webhook"];
562
+ if (options["no-hermes"]) {
563
+ return names.filter((name) => name !== "hermes" && name !== "hermes-dashboard");
564
+ }
565
+ if (options["no-dashboard"]) {
566
+ return names.filter((name) => name !== "hermes-dashboard");
567
+ }
568
+ return names;
569
+ }
570
+
556
571
  function readPid(filePath) {
557
572
  if (!fs.existsSync(filePath)) {
558
573
  return null;
@@ -750,10 +765,17 @@ function startLocal(options) {
750
765
  startManagedProcess(config, "openilink", oih, [], env);
751
766
  if (hermes) {
752
767
  startManagedProcess(config, "hermes", hermes, ["gateway", "run"], env);
768
+ if (!options["no-dashboard"]) {
769
+ startManagedProcess(config, "hermes-dashboard", hermes, ["dashboard", "--host", "127.0.0.1", "--port", String(DEFAULT_HERMES_DASHBOARD_PORT), "--no-open"], env);
770
+ }
753
771
  } else {
754
772
  console.log("hermes: skipped (--no-hermes)");
773
+ console.log("hermes-dashboard: skipped (--no-hermes)");
755
774
  }
756
775
  console.log(`OpeniLink Hub: ${config.openilink?.publicOrigin || DEFAULT_OPENILINK_ORIGIN}`);
776
+ if (hermes && !options["no-dashboard"]) {
777
+ console.log(`Hermes Dashboard: http://127.0.0.1:${DEFAULT_HERMES_DASHBOARD_PORT}`);
778
+ }
757
779
  console.log(`Webhook health: http://127.0.0.1:${config.webhook?.port || DEFAULT_WEBHOOK_PORT}/health`);
758
780
  return 0;
759
781
  }
@@ -777,10 +799,12 @@ async function statusLocal() {
777
799
  return 1;
778
800
  }
779
801
 
780
- for (const name of ["hermes", "openilink", "webhook"]) {
802
+ for (const name of localProcessNames()) {
781
803
  const pid = readPid(pidPath(config, name));
782
804
  console.log(`${name}: ${processRunning(pid) ? `running (pid ${pid})` : "stopped"}`);
783
805
  }
806
+ const dashboardHealth = await httpGet(`http://127.0.0.1:${DEFAULT_HERMES_DASHBOARD_PORT}`);
807
+ console.log(`hermes dashboard: ${dashboardHealth.ok ? `ok (${dashboardHealth.statusCode})` : "unreachable"}`);
784
808
  const health = await httpGet(`http://127.0.0.1:${config.webhook?.port || DEFAULT_WEBHOOK_PORT}/health`);
785
809
  console.log(`webhook health: ${health.ok ? `ok (${health.statusCode})` : "unreachable"}`);
786
810
  return 0;
@@ -805,7 +829,7 @@ function logsLocal() {
805
829
  return 1;
806
830
  }
807
831
 
808
- const files = ["hermes", "openilink", "webhook"].map((name) => logPath(config, name)).filter((filePath) => fs.existsSync(filePath));
832
+ const files = localProcessNames().map((name) => logPath(config, name)).filter((filePath) => fs.existsSync(filePath));
809
833
  if (files.length === 0) {
810
834
  console.error("No local runtime logs found.");
811
835
  return 1;
@@ -845,6 +869,7 @@ function stopLocal() {
845
869
 
846
870
  stopManagedProcess(config, "webhook");
847
871
  stopManagedProcess(config, "openilink");
872
+ stopManagedProcess(config, "hermes-dashboard");
848
873
  stopManagedProcess(config, "hermes");
849
874
  return 0;
850
875
  }
@@ -903,7 +928,7 @@ function clean(options) {
903
928
 
904
929
  const config = fs.existsSync(configPath()) ? readConfig() : null;
905
930
  if (config) {
906
- for (const name of ["webhook", "openilink", "hermes"]) {
931
+ for (const name of ["webhook", "openilink", "hermes-dashboard", "hermes"]) {
907
932
  stopManagedProcess({ ...config, runtime: { ...config.runtime, dir: config.runtime?.dir || path.join(configHome(), "runtime") } }, name);
908
933
  }
909
934
  const docker = dockerComposeAvailable();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodus-wechat",
3
- "version": "0.7.1",
3
+ "version": "0.7.2",
4
4
  "description": "CLI installer for Nodus WeChat, Hermes, and the local OpeniLink webhook runtime.",
5
5
  "license": "MIT",
6
6
  "private": false,