nodus-wechat 0.6.2 → 0.7.1
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 +4 -4
- package/bin/nodus-wechat.js +56 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,6 +18,7 @@ npx nodus-wechat install-openilink
|
|
|
18
18
|
npx nodus-wechat doctor
|
|
19
19
|
npx nodus-wechat start
|
|
20
20
|
npx nodus-wechat start --no-install
|
|
21
|
+
npx nodus-wechat start --no-hermes
|
|
21
22
|
npx nodus-wechat start --docker
|
|
22
23
|
npx nodus-wechat status
|
|
23
24
|
npx nodus-wechat logs
|
|
@@ -52,8 +53,8 @@ the official OpeniLink installer.
|
|
|
52
53
|
- Writes runtime `.env`, Docker Compose, webhook server, helper scripts, and the OpeniLink reply plugin.
|
|
53
54
|
- Stores gateway base URL, api key, model, Hermes paths, OpeniLink origin, webhook port, and runtime path.
|
|
54
55
|
- 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`.
|
|
55
|
-
- Starts/stops the local
|
|
56
|
-
- Installs OpeniLink automatically during `start` when the native
|
|
56
|
+
- Starts/stops Hermes Gateway, OpeniLink, and the local webhook with native host processes by default.
|
|
57
|
+
- Installs Hermes and OpeniLink automatically during `start` when the native CLIs are missing.
|
|
57
58
|
- Keeps Docker Compose available only when `--docker` is passed.
|
|
58
59
|
- Removes Nodus WeChat config/runtime files with `uninstall --yes`.
|
|
59
60
|
- Cleans Nodus WeChat config/runtime plus generated Hermes settings with `clean --yes`.
|
|
@@ -77,9 +78,8 @@ the config generated by this CLI.
|
|
|
77
78
|
|
|
78
79
|
## Current non-goals
|
|
79
80
|
|
|
80
|
-
- Does not run the Hermes installer unless `--install-hermes` or `install-hermes` is explicitly requested.
|
|
81
81
|
- Does not automate, inject into, read, or control WeChat directly.
|
|
82
|
-
- Does not
|
|
82
|
+
- Does not install a LaunchAgent or system service; `start` uses managed host processes that `stop` can terminate.
|
|
83
83
|
- Does not redeem real CDKs or mutate sub2api accounts; the bundled webhook keeps the existing dry-run POC boundary.
|
|
84
84
|
|
|
85
85
|
## Runtime wiring
|
package/bin/nodus-wechat.js
CHANGED
|
@@ -8,7 +8,7 @@ const os = require("node:os");
|
|
|
8
8
|
const path = require("node:path");
|
|
9
9
|
const childProcess = require("node:child_process");
|
|
10
10
|
|
|
11
|
-
const VERSION = "0.
|
|
11
|
+
const VERSION = "0.7.1";
|
|
12
12
|
const DEFAULT_BASE_URL = "https://api.nodus.sbs/";
|
|
13
13
|
const DEFAULT_MODEL = "gpt-5.5";
|
|
14
14
|
const DEFAULT_OPENILINK_ORIGIN = "http://localhost:9800";
|
|
@@ -43,7 +43,7 @@ Usage:
|
|
|
43
43
|
nodus-wechat install-hermes
|
|
44
44
|
nodus-wechat install-openilink
|
|
45
45
|
nodus-wechat doctor
|
|
46
|
-
nodus-wechat start [--docker] [--no-install]
|
|
46
|
+
nodus-wechat start [--docker] [--no-install] [--no-hermes]
|
|
47
47
|
nodus-wechat status [--docker]
|
|
48
48
|
nodus-wechat logs [--docker]
|
|
49
49
|
nodus-wechat stop [--docker]
|
|
@@ -56,7 +56,7 @@ Commands:
|
|
|
56
56
|
install-openilink
|
|
57
57
|
Install OpeniLink Hub native CLI with the official installer.
|
|
58
58
|
doctor Check local prerequisites and configuration.
|
|
59
|
-
start Start OpeniLink
|
|
59
|
+
start Start Hermes Gateway, OpeniLink, and webhook on the host by default.
|
|
60
60
|
status Show local process status.
|
|
61
61
|
logs Follow local runtime logs.
|
|
62
62
|
stop Stop the local runtime.
|
|
@@ -78,7 +78,7 @@ function parseArgs(argv) {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
const key = item.slice(2);
|
|
81
|
-
if (key === "help" || key === "yes" || key === "install-hermes" || key === "docker" || key === "no-install") {
|
|
81
|
+
if (key === "help" || key === "yes" || key === "install-hermes" || key === "docker" || key === "no-install" || key === "no-hermes") {
|
|
82
82
|
result[key] = true;
|
|
83
83
|
continue;
|
|
84
84
|
}
|
|
@@ -247,12 +247,24 @@ function openiLinkInstallCommand() {
|
|
|
247
247
|
}
|
|
248
248
|
|
|
249
249
|
function runHermesInstaller(hermesDir) {
|
|
250
|
+
const checkoutDir = path.join(hermesDir, "hermes-agent");
|
|
251
|
+
if (fs.existsSync(checkoutDir) && fs.existsSync(path.join(checkoutDir, ".git")) && !fs.existsSync(path.join(checkoutDir, "pyproject.toml"))) {
|
|
252
|
+
fs.rmSync(checkoutDir, { recursive: true, force: true });
|
|
253
|
+
}
|
|
254
|
+
|
|
250
255
|
const args = ["--skip-setup", "--hermes-home", hermesDir];
|
|
251
256
|
const command = `${hermesInstallCommand()} ${args.map(shellQuote).join(" ")}`;
|
|
252
257
|
const result = childProcess.spawnSync(command, {
|
|
253
258
|
shell: true,
|
|
254
259
|
stdio: "inherit",
|
|
255
|
-
env: {
|
|
260
|
+
env: {
|
|
261
|
+
...process.env,
|
|
262
|
+
HERMES_HOME: hermesDir,
|
|
263
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
264
|
+
GIT_CONFIG_COUNT: "1",
|
|
265
|
+
GIT_CONFIG_KEY_0: "url.https://github.com/.insteadOf",
|
|
266
|
+
GIT_CONFIG_VALUE_0: "git@github.com:",
|
|
267
|
+
},
|
|
256
268
|
});
|
|
257
269
|
|
|
258
270
|
if (result.error) {
|
|
@@ -377,7 +389,7 @@ function setup(options) {
|
|
|
377
389
|
console.log(`OpeniLink Hub: ${config.openilink.publicOrigin}`);
|
|
378
390
|
console.log(`Webhook URL for OpeniLink: http://poc-webhook:${config.webhook.port}/webhook`);
|
|
379
391
|
console.log("Runtime mode: host process by default; Docker is used only with `--docker`.");
|
|
380
|
-
console.log("Run `nodus-wechat start` to start the local host runtime
|
|
392
|
+
console.log("Run `nodus-wechat start` to start Hermes Gateway plus the local host runtime.");
|
|
381
393
|
}
|
|
382
394
|
|
|
383
395
|
function installHermes() {
|
|
@@ -519,6 +531,16 @@ function commandPath(name) {
|
|
|
519
531
|
return result.stdout.trim() || null;
|
|
520
532
|
}
|
|
521
533
|
|
|
534
|
+
function hermesPath(config) {
|
|
535
|
+
return (
|
|
536
|
+
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)
|
|
541
|
+
);
|
|
542
|
+
}
|
|
543
|
+
|
|
522
544
|
function runtimePath(config, name) {
|
|
523
545
|
return path.join(config.runtime.dir, name);
|
|
524
546
|
}
|
|
@@ -597,6 +619,7 @@ function localRuntimeEnv(config) {
|
|
|
597
619
|
return {
|
|
598
620
|
...process.env,
|
|
599
621
|
...env,
|
|
622
|
+
HERMES_HOME: config.hermes?.home || hermesHome(),
|
|
600
623
|
LISTEN: `:${config.openilink?.port || DEFAULT_OPENILINK_PORT}`,
|
|
601
624
|
RP_ORIGIN: config.openilink?.publicOrigin || DEFAULT_OPENILINK_ORIGIN,
|
|
602
625
|
RP_ID: config.openilink?.rpId || DEFAULT_OPENILINK_RP_ID,
|
|
@@ -682,6 +705,24 @@ function startLocal(options) {
|
|
|
682
705
|
return 1;
|
|
683
706
|
}
|
|
684
707
|
|
|
708
|
+
let hermes = options["no-hermes"] ? null : hermesPath(config);
|
|
709
|
+
if (!hermes && !options["no-hermes"]) {
|
|
710
|
+
if (options["no-install"]) {
|
|
711
|
+
console.error("Hermes CLI `hermes` is not installed.");
|
|
712
|
+
console.error("Run: nodus-wechat install-hermes");
|
|
713
|
+
return 1;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
console.log("Hermes CLI `hermes` is not installed; installing it now.");
|
|
717
|
+
runHermesInstaller(config.hermes?.home || hermesHome());
|
|
718
|
+
hermes = hermesPath(config);
|
|
719
|
+
if (!hermes) {
|
|
720
|
+
console.error("Hermes installer completed, but `hermes` is still not on PATH.");
|
|
721
|
+
console.error("Open a new terminal or add the installed Hermes path to PATH, then rerun `nodus-wechat start`.");
|
|
722
|
+
return 1;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
|
|
685
726
|
let oih = commandPath("oih");
|
|
686
727
|
if (!oih) {
|
|
687
728
|
if (options["no-install"]) {
|
|
@@ -707,6 +748,11 @@ function startLocal(options) {
|
|
|
707
748
|
const webhookPath = path.join(config.runtime.dir, "poc-webhook", "server.py");
|
|
708
749
|
startManagedProcess(config, "webhook", python, [webhookPath], env);
|
|
709
750
|
startManagedProcess(config, "openilink", oih, [], env);
|
|
751
|
+
if (hermes) {
|
|
752
|
+
startManagedProcess(config, "hermes", hermes, ["gateway", "run"], env);
|
|
753
|
+
} else {
|
|
754
|
+
console.log("hermes: skipped (--no-hermes)");
|
|
755
|
+
}
|
|
710
756
|
console.log(`OpeniLink Hub: ${config.openilink?.publicOrigin || DEFAULT_OPENILINK_ORIGIN}`);
|
|
711
757
|
console.log(`Webhook health: http://127.0.0.1:${config.webhook?.port || DEFAULT_WEBHOOK_PORT}/health`);
|
|
712
758
|
return 0;
|
|
@@ -731,7 +777,7 @@ async function statusLocal() {
|
|
|
731
777
|
return 1;
|
|
732
778
|
}
|
|
733
779
|
|
|
734
|
-
for (const name of ["openilink", "webhook"]) {
|
|
780
|
+
for (const name of ["hermes", "openilink", "webhook"]) {
|
|
735
781
|
const pid = readPid(pidPath(config, name));
|
|
736
782
|
console.log(`${name}: ${processRunning(pid) ? `running (pid ${pid})` : "stopped"}`);
|
|
737
783
|
}
|
|
@@ -759,7 +805,7 @@ function logsLocal() {
|
|
|
759
805
|
return 1;
|
|
760
806
|
}
|
|
761
807
|
|
|
762
|
-
const files = ["openilink", "webhook"].map((name) => logPath(config, name)).filter((filePath) => fs.existsSync(filePath));
|
|
808
|
+
const files = ["hermes", "openilink", "webhook"].map((name) => logPath(config, name)).filter((filePath) => fs.existsSync(filePath));
|
|
763
809
|
if (files.length === 0) {
|
|
764
810
|
console.error("No local runtime logs found.");
|
|
765
811
|
return 1;
|
|
@@ -799,6 +845,7 @@ function stopLocal() {
|
|
|
799
845
|
|
|
800
846
|
stopManagedProcess(config, "webhook");
|
|
801
847
|
stopManagedProcess(config, "openilink");
|
|
848
|
+
stopManagedProcess(config, "hermes");
|
|
802
849
|
return 0;
|
|
803
850
|
}
|
|
804
851
|
|
|
@@ -856,7 +903,7 @@ function clean(options) {
|
|
|
856
903
|
|
|
857
904
|
const config = fs.existsSync(configPath()) ? readConfig() : null;
|
|
858
905
|
if (config) {
|
|
859
|
-
for (const name of ["webhook", "openilink"]) {
|
|
906
|
+
for (const name of ["webhook", "openilink", "hermes"]) {
|
|
860
907
|
stopManagedProcess({ ...config, runtime: { ...config.runtime, dir: config.runtime?.dir || path.join(configHome(), "runtime") } }, name);
|
|
861
908
|
}
|
|
862
909
|
const docker = dockerComposeAvailable();
|