@matelink/cli 2026.4.17 → 2026.4.18
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/bin/matecli.mjs +152 -10
- package/package.json +1 -1
package/bin/matecli.mjs
CHANGED
|
@@ -53,6 +53,102 @@ const DEFAULT_GATEWAY_SCOPES = [
|
|
|
53
53
|
].join(",");
|
|
54
54
|
const SESSION_CONTEXT_MIN_TOKENS = 1024;
|
|
55
55
|
const CLI_ENTRY = fileURLToPath(import.meta.url);
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
function buildPathString(values) {
|
|
59
|
+
const entries = [];
|
|
60
|
+
const seen = new Set();
|
|
61
|
+
for (const value of values) {
|
|
62
|
+
const raw = String(value ?? "").trim();
|
|
63
|
+
if (!raw) continue;
|
|
64
|
+
for (const part of raw.split(":")) {
|
|
65
|
+
const normalized = part.trim();
|
|
66
|
+
if (!normalized || seen.has(normalized)) continue;
|
|
67
|
+
seen.add(normalized);
|
|
68
|
+
entries.push(normalized);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return entries.join(":");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function resolveSiblingBinDirs(executablePath) {
|
|
75
|
+
const normalized = String(executablePath ?? "").trim();
|
|
76
|
+
if (!normalized) return [];
|
|
77
|
+
const binDir = path.dirname(normalized);
|
|
78
|
+
return [binDir];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function resolveOpenClawBinaryCandidates() {
|
|
82
|
+
const homeDir = os.homedir();
|
|
83
|
+
const candidates = new Set();
|
|
84
|
+
const addCandidate = (candidate) => {
|
|
85
|
+
const normalized = String(candidate ?? "").trim();
|
|
86
|
+
if (!normalized) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
if (fs.existsSync(normalized)) {
|
|
91
|
+
candidates.add(fs.realpathSync(normalized));
|
|
92
|
+
}
|
|
93
|
+
} catch {
|
|
94
|
+
if (fs.existsSync(normalized)) {
|
|
95
|
+
candidates.add(normalized);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
for (const nodeCandidate of resolveNodeCandidates()) {
|
|
101
|
+
addCandidate(path.join(path.dirname(nodeCandidate), "openclaw"));
|
|
102
|
+
}
|
|
103
|
+
addCandidate(path.join(homeDir, ".nvm", "current", "bin", "openclaw"));
|
|
104
|
+
addCandidate(path.join(homeDir, ".volta", "bin", "openclaw"));
|
|
105
|
+
addCandidate("/opt/homebrew/bin/openclaw");
|
|
106
|
+
addCandidate("/usr/local/bin/openclaw");
|
|
107
|
+
addCandidate("/usr/bin/openclaw");
|
|
108
|
+
|
|
109
|
+
const whichOpenClaw = runCommand("which", ["openclaw"]);
|
|
110
|
+
if (whichOpenClaw.status === 0) {
|
|
111
|
+
const resolved = String(whichOpenClaw.stdout ?? "").trim();
|
|
112
|
+
if (resolved && fs.existsSync(resolved)) {
|
|
113
|
+
addCandidate(resolved);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return [...candidates];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function resolveOpenClawBinaryPath() {
|
|
121
|
+
for (const candidate of resolveOpenClawBinaryCandidates()) {
|
|
122
|
+
if (candidate && fs.existsSync(candidate)) {
|
|
123
|
+
return candidate;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return "openclaw";
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function buildBridgeRuntimeEnv(extraEnv = {}) {
|
|
130
|
+
const homeDir = os.homedir();
|
|
131
|
+
const nodePath = resolveBridgeServiceNodePath();
|
|
132
|
+
const openclawPath = resolveOpenClawBinaryPath();
|
|
133
|
+
const pathValue = buildPathString([
|
|
134
|
+
...resolveSiblingBinDirs(nodePath),
|
|
135
|
+
...resolveSiblingBinDirs(openclawPath),
|
|
136
|
+
"/opt/homebrew/bin",
|
|
137
|
+
"/usr/local/bin",
|
|
138
|
+
"/usr/bin",
|
|
139
|
+
"/bin",
|
|
140
|
+
"/usr/sbin",
|
|
141
|
+
"/sbin",
|
|
142
|
+
path.join(homeDir, ".volta", "bin"),
|
|
143
|
+
path.join(homeDir, ".nvm", "current", "bin"),
|
|
144
|
+
process.env.PATH ?? "",
|
|
145
|
+
]);
|
|
146
|
+
return {
|
|
147
|
+
...process.env,
|
|
148
|
+
...extraEnv,
|
|
149
|
+
PATH: pathValue,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
56
152
|
const CLI_LANGUAGE = detectCliLanguage();
|
|
57
153
|
const CLI_I18N = {
|
|
58
154
|
zh: {
|
|
@@ -728,6 +824,7 @@ function listFixedMemoryFiles(workspaceRoot) {
|
|
|
728
824
|
workspaceRoot,
|
|
729
825
|
relativePath,
|
|
730
826
|
absolutePath,
|
|
827
|
+
includeContent: true,
|
|
731
828
|
});
|
|
732
829
|
});
|
|
733
830
|
}
|
|
@@ -1375,6 +1472,40 @@ function extractErrorMessage(decoded, fallback) {
|
|
|
1375
1472
|
return fallback;
|
|
1376
1473
|
}
|
|
1377
1474
|
|
|
1475
|
+
function formatErrorDetails(error) {
|
|
1476
|
+
if (!(error instanceof Error)) {
|
|
1477
|
+
return String(error ?? "");
|
|
1478
|
+
}
|
|
1479
|
+
const details = [];
|
|
1480
|
+
if (error.name && error.name !== "Error") {
|
|
1481
|
+
details.push(`name=${error.name}`);
|
|
1482
|
+
}
|
|
1483
|
+
if (error.code) {
|
|
1484
|
+
details.push(`code=${String(error.code)}`);
|
|
1485
|
+
}
|
|
1486
|
+
if (error.errno) {
|
|
1487
|
+
details.push(`errno=${String(error.errno)}`);
|
|
1488
|
+
}
|
|
1489
|
+
if (error.type) {
|
|
1490
|
+
details.push(`type=${String(error.type)}`);
|
|
1491
|
+
}
|
|
1492
|
+
if (error.cause && typeof error.cause === "object") {
|
|
1493
|
+
const cause = error.cause;
|
|
1494
|
+
if (cause?.code) {
|
|
1495
|
+
details.push(`cause.code=${String(cause.code)}`);
|
|
1496
|
+
}
|
|
1497
|
+
if (cause?.errno) {
|
|
1498
|
+
details.push(`cause.errno=${String(cause.errno)}`);
|
|
1499
|
+
}
|
|
1500
|
+
if (cause?.message) {
|
|
1501
|
+
details.push(`cause=${String(cause.message)}`);
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
return details.length > 0
|
|
1505
|
+
? `${error.message} [${details.join(", ")}]`
|
|
1506
|
+
: error.message;
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1378
1509
|
async function fetchWithTimeout(url, options = {}, timeoutMs = DEFAULT_NETWORK_TIMEOUT_MS) {
|
|
1379
1510
|
const controller = new AbortController();
|
|
1380
1511
|
const timer = setTimeout(() => controller.abort(new Error(`fetch timeout after ${timeoutMs}ms`)), timeoutMs);
|
|
@@ -1383,6 +1514,8 @@ async function fetchWithTimeout(url, options = {}, timeoutMs = DEFAULT_NETWORK_T
|
|
|
1383
1514
|
...options,
|
|
1384
1515
|
signal: controller.signal,
|
|
1385
1516
|
});
|
|
1517
|
+
} catch (error) {
|
|
1518
|
+
throw new Error(formatErrorDetails(error));
|
|
1386
1519
|
} finally {
|
|
1387
1520
|
clearTimeout(timer);
|
|
1388
1521
|
}
|
|
@@ -1756,7 +1889,9 @@ function resolveBridgeServiceNodePath() {
|
|
|
1756
1889
|
function writeBridgeLaunchScript(installConfig) {
|
|
1757
1890
|
const scriptPath = resolveBridgeLaunchScriptPath();
|
|
1758
1891
|
fs.mkdirSync(path.dirname(scriptPath), { recursive: true });
|
|
1759
|
-
const defaultPath = [
|
|
1892
|
+
const defaultPath = buildPathString([
|
|
1893
|
+
...resolveSiblingBinDirs(installConfig.nodePath),
|
|
1894
|
+
...resolveSiblingBinDirs(installConfig.openclawPath),
|
|
1760
1895
|
"/opt/homebrew/bin",
|
|
1761
1896
|
"/usr/local/bin",
|
|
1762
1897
|
"/usr/bin",
|
|
@@ -1765,11 +1900,16 @@ function writeBridgeLaunchScript(installConfig) {
|
|
|
1765
1900
|
"/sbin",
|
|
1766
1901
|
path.join(os.homedir(), ".volta", "bin"),
|
|
1767
1902
|
path.join(os.homedir(), ".nvm", "current", "bin"),
|
|
1768
|
-
]
|
|
1769
|
-
const knownNodeCandidates = resolveNodeCandidates()
|
|
1770
|
-
|
|
1771
|
-
.
|
|
1772
|
-
|
|
1903
|
+
]);
|
|
1904
|
+
const knownNodeCandidates = [installConfig.nodePath, ...resolveNodeCandidates()]
|
|
1905
|
+
.filter(Boolean)
|
|
1906
|
+
.filter((candidate, index, values) => values.indexOf(candidate) === index);
|
|
1907
|
+
const candidateChecks = knownNodeCandidates.length > 0
|
|
1908
|
+
? `${knownNodeCandidates
|
|
1909
|
+
.map((candidate, index) => `${index === 0 ? 'if' : 'elif'} [ -x '${escapePosixShellSingleQuoted(candidate)}' ]; then NODE_BIN='${escapePosixShellSingleQuoted(candidate)}';`)
|
|
1910
|
+
.join("\n")}
|
|
1911
|
+
fi`
|
|
1912
|
+
: "";
|
|
1773
1913
|
const fallbackLine = buildPosixShellExec("node", installConfig.args);
|
|
1774
1914
|
const script = [
|
|
1775
1915
|
"#!/bin/sh",
|
|
@@ -1806,6 +1946,7 @@ function ensureBridgeServiceInstallConfig({ relayUrl, gatewayBaseUrl }) {
|
|
|
1806
1946
|
stdoutLog: path.join(logDir, "bridge.stdout.log"),
|
|
1807
1947
|
stderrLog: path.join(logDir, "bridge.stderr.log"),
|
|
1808
1948
|
nodePath: resolveBridgeServiceNodePath(),
|
|
1949
|
+
openclawPath: resolveOpenClawBinaryPath(),
|
|
1809
1950
|
scriptPath: CLI_ENTRY,
|
|
1810
1951
|
args: bridgeInvocationArgs({ relayUrl, gatewayBaseUrl }),
|
|
1811
1952
|
};
|
|
@@ -2610,7 +2751,7 @@ async function readRelayNextGatewayRequest({
|
|
|
2610
2751
|
if (message.includes("timeout")) {
|
|
2611
2752
|
return null;
|
|
2612
2753
|
}
|
|
2613
|
-
throw
|
|
2754
|
+
throw new Error(`relay gateway poll transport failed: GET ${url} -> ${message}`);
|
|
2614
2755
|
}
|
|
2615
2756
|
|
|
2616
2757
|
if (response.status === 204) {
|
|
@@ -3199,8 +3340,9 @@ async function callGatewayRpcLocalViaCli({
|
|
|
3199
3340
|
args.push("--token", gatewayAuthToken);
|
|
3200
3341
|
}
|
|
3201
3342
|
|
|
3202
|
-
const child = spawn(
|
|
3343
|
+
const child = spawn(resolveOpenClawBinaryPath(), args, {
|
|
3203
3344
|
stdio: ["ignore", "pipe", "pipe"],
|
|
3345
|
+
env: buildBridgeRuntimeEnv(),
|
|
3204
3346
|
});
|
|
3205
3347
|
let timedOut = false;
|
|
3206
3348
|
const timeout = setTimeout(() => {
|
|
@@ -3629,12 +3771,12 @@ function startRelayBridgeDetached({
|
|
|
3629
3771
|
}
|
|
3630
3772
|
|
|
3631
3773
|
const child = spawn(
|
|
3632
|
-
|
|
3774
|
+
resolveBridgeServiceNodePath(),
|
|
3633
3775
|
[CLI_ENTRY, "bridge", "--relay", relayUrl, "--gateway", gatewayBaseUrl],
|
|
3634
3776
|
{
|
|
3635
3777
|
detached: true,
|
|
3636
3778
|
stdio: "ignore",
|
|
3637
|
-
env:
|
|
3779
|
+
env: buildBridgeRuntimeEnv(),
|
|
3638
3780
|
windowsHide: process.platform === "win32",
|
|
3639
3781
|
},
|
|
3640
3782
|
);
|