claw-control-center 0.1.7 → 0.1.9
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/index.cjs
CHANGED
|
@@ -5449,10 +5449,10 @@ function resolvePluginConfig(config) {
|
|
|
5449
5449
|
function resolvePluginConfigWithHostDefaults(configPath, config) {
|
|
5450
5450
|
const resolved = resolvePluginConfig(config);
|
|
5451
5451
|
const hostConfig = readHostGatewayConfig(resolveHostConfigPath(configPath));
|
|
5452
|
-
if (!resolved.gateway.baseUrl
|
|
5452
|
+
if (hostConfig.baseUrl && (!resolved.gateway.baseUrl || shouldPreferHostGateway(resolved.gateway.baseUrl, hostConfig.baseUrl))) {
|
|
5453
5453
|
resolved.gateway.baseUrl = hostConfig.baseUrl;
|
|
5454
5454
|
}
|
|
5455
|
-
if (!resolved.gateway.secret
|
|
5455
|
+
if (hostConfig.secret && (!resolved.gateway.secret || resolved.gateway.baseUrl === hostConfig.baseUrl)) {
|
|
5456
5456
|
resolved.gateway.secret = hostConfig.secret;
|
|
5457
5457
|
}
|
|
5458
5458
|
if (!resolved.hub53ai.botId && hostConfig.hub53ai?.botId) {
|
|
@@ -5466,6 +5466,28 @@ function resolvePluginConfigWithHostDefaults(configPath, config) {
|
|
|
5466
5466
|
}
|
|
5467
5467
|
return resolved;
|
|
5468
5468
|
}
|
|
5469
|
+
function shouldPreferHostGateway(configuredBaseUrl, hostBaseUrl) {
|
|
5470
|
+
if (configuredBaseUrl === hostBaseUrl) {
|
|
5471
|
+
return false;
|
|
5472
|
+
}
|
|
5473
|
+
const configured = parseGatewayUrl(configuredBaseUrl);
|
|
5474
|
+
const host = parseGatewayUrl(hostBaseUrl);
|
|
5475
|
+
if (!configured || !host) {
|
|
5476
|
+
return false;
|
|
5477
|
+
}
|
|
5478
|
+
return configured.isLoopback && host.isLoopback;
|
|
5479
|
+
}
|
|
5480
|
+
function parseGatewayUrl(value) {
|
|
5481
|
+
try {
|
|
5482
|
+
const url = new URL(value);
|
|
5483
|
+
const hostname = url.hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
5484
|
+
return {
|
|
5485
|
+
isLoopback: hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1"
|
|
5486
|
+
};
|
|
5487
|
+
} catch {
|
|
5488
|
+
return void 0;
|
|
5489
|
+
}
|
|
5490
|
+
}
|
|
5469
5491
|
function sanitizePluginConfig(config) {
|
|
5470
5492
|
if (!config) {
|
|
5471
5493
|
return {};
|
|
@@ -8859,32 +8881,84 @@ function toRecord3(value) {
|
|
|
8859
8881
|
|
|
8860
8882
|
// src/install-qclaw.ts
|
|
8861
8883
|
var import_node_crypto4 = require("crypto");
|
|
8862
|
-
var import_promises4 = require("
|
|
8884
|
+
var import_promises4 = require("readline/promises");
|
|
8885
|
+
var import_promises5 = require("fs/promises");
|
|
8863
8886
|
var import_node_fs4 = require("fs");
|
|
8887
|
+
var import_node_os2 = require("os");
|
|
8864
8888
|
var import_node_path6 = require("path");
|
|
8889
|
+
var import_yaml = require("yaml");
|
|
8865
8890
|
var PLUGIN_ID = "claw-control-center";
|
|
8866
8891
|
var LEGACY_PLUGIN_ID = "53ai-openclaw";
|
|
8867
8892
|
var COPY_ITEMS = ["dist", "openclaw.plugin.json", "package.json", "bin", "web-dist"];
|
|
8893
|
+
var HERMES_PLATFORM_ID = "53aihub";
|
|
8894
|
+
var HERMES_PLUGIN_KEY = `platforms/${HERMES_PLATFORM_ID}`;
|
|
8895
|
+
var HERMES_ENV_KEYS = {
|
|
8896
|
+
botId: "HUB53AI_BOT_ID",
|
|
8897
|
+
secret: "HUB53AI_SECRET",
|
|
8898
|
+
wsUrl: "HUB53AI_WS_URL"
|
|
8899
|
+
};
|
|
8900
|
+
var SUPPORTED_ARGS = /* @__PURE__ */ new Set([
|
|
8901
|
+
"gateway",
|
|
8902
|
+
"bot-id",
|
|
8903
|
+
"secret",
|
|
8904
|
+
"prefer-responses-api",
|
|
8905
|
+
"gateway-model",
|
|
8906
|
+
"hub-ws-url",
|
|
8907
|
+
"hub-bot-id",
|
|
8908
|
+
"hub-secret",
|
|
8909
|
+
"hub-enabled",
|
|
8910
|
+
"extensions-dir",
|
|
8911
|
+
"config-path",
|
|
8912
|
+
"console-host",
|
|
8913
|
+
"console-port"
|
|
8914
|
+
]);
|
|
8868
8915
|
async function installIntoQClaw(input) {
|
|
8869
8916
|
return installIntoHost(input, "QClaw");
|
|
8870
8917
|
}
|
|
8871
8918
|
async function installIntoOpenClaw(input) {
|
|
8872
8919
|
return installIntoHost(input, "OpenClaw");
|
|
8873
8920
|
}
|
|
8921
|
+
async function installIntoHermes(input) {
|
|
8922
|
+
const hubWsUrl = input.hubWsUrl?.trim();
|
|
8923
|
+
const hubBotId = input.hubBotId?.trim();
|
|
8924
|
+
const hubSecret = input.hubSecret?.trim();
|
|
8925
|
+
if (!hubWsUrl || !hubBotId || !hubSecret) {
|
|
8926
|
+
throw new Error("Hermes install requires --hub-ws-url, --hub-bot-id, and --hub-secret");
|
|
8927
|
+
}
|
|
8928
|
+
const platformsDir = normalizeHermesPlatformsDir(input.extensionsDir);
|
|
8929
|
+
const destination = (0, import_node_path6.join)(platformsDir, HERMES_PLATFORM_ID);
|
|
8930
|
+
await (0, import_promises5.mkdir)(destination, { recursive: true });
|
|
8931
|
+
await copyHermesPlatformPackage(input.packageRoot, destination);
|
|
8932
|
+
await updateHermesConfig(input.configPath);
|
|
8933
|
+
await updateHermesEnv(input.configPath, {
|
|
8934
|
+
botId: hubBotId,
|
|
8935
|
+
secret: hubSecret,
|
|
8936
|
+
wsUrl: hubWsUrl
|
|
8937
|
+
});
|
|
8938
|
+
return {
|
|
8939
|
+
configPath: input.configPath,
|
|
8940
|
+
extensionsDir: platformsDir,
|
|
8941
|
+
destination,
|
|
8942
|
+
hub53aiConfigured: true,
|
|
8943
|
+
pluginBuild: await readHermesPluginBuildInfo(destination)
|
|
8944
|
+
};
|
|
8945
|
+
}
|
|
8874
8946
|
async function installIntoHost(input, hostLabel) {
|
|
8875
|
-
await (0,
|
|
8947
|
+
await (0, import_promises5.mkdir)(input.extensionsDir, { recursive: true });
|
|
8876
8948
|
const destination = (0, import_node_path6.join)(input.extensionsDir, PLUGIN_ID);
|
|
8877
|
-
await (0,
|
|
8949
|
+
await (0, import_promises5.mkdir)(destination, { recursive: true });
|
|
8878
8950
|
await copyPublishablePackage(input.packageRoot, destination);
|
|
8879
|
-
await (0,
|
|
8951
|
+
await (0, import_promises5.mkdir)((0, import_node_path6.dirname)(input.configPath), { recursive: true });
|
|
8880
8952
|
const config = await readOpenClawConfig(input.configPath);
|
|
8881
8953
|
const inferredGateway = inferGatewaySettings(config);
|
|
8882
8954
|
const inferredHub53AI = inferHub53AISettings(config);
|
|
8883
|
-
const
|
|
8955
|
+
const explicitGatewayBaseUrl = input.gateway?.trim();
|
|
8956
|
+
const explicitGatewaySecret = input.secret?.trim();
|
|
8957
|
+
const gatewayBaseUrl = explicitGatewayBaseUrl || inferredGateway.baseUrl;
|
|
8884
8958
|
if (!gatewayBaseUrl) {
|
|
8885
8959
|
throw new Error(`missing gateway URL and no local ${hostLabel} gateway could be inferred`);
|
|
8886
8960
|
}
|
|
8887
|
-
const secret =
|
|
8961
|
+
const secret = explicitGatewaySecret || inferredGateway.secret;
|
|
8888
8962
|
if (!secret) {
|
|
8889
8963
|
throw new Error(`missing gateway secret and no local ${hostLabel} gateway token could be inferred`);
|
|
8890
8964
|
}
|
|
@@ -8919,8 +8993,16 @@ async function installIntoHost(input, hostLabel) {
|
|
|
8919
8993
|
const previousEntry = ensureObject(entries, PLUGIN_ID);
|
|
8920
8994
|
const previousConfig = ensureObject(previousEntry, "config");
|
|
8921
8995
|
const previousGateway = ensureObject(previousConfig, "gateway");
|
|
8922
|
-
|
|
8923
|
-
|
|
8996
|
+
if (explicitGatewayBaseUrl) {
|
|
8997
|
+
previousGateway.baseUrl = explicitGatewayBaseUrl;
|
|
8998
|
+
} else {
|
|
8999
|
+
delete previousGateway.baseUrl;
|
|
9000
|
+
}
|
|
9001
|
+
if (explicitGatewaySecret) {
|
|
9002
|
+
previousGateway.secret = explicitGatewaySecret;
|
|
9003
|
+
} else {
|
|
9004
|
+
delete previousGateway.secret;
|
|
9005
|
+
}
|
|
8924
9006
|
previousGateway.preferResponsesApi = preferResponsesApi;
|
|
8925
9007
|
if (botId) {
|
|
8926
9008
|
previousGateway.botId = botId;
|
|
@@ -8961,7 +9043,7 @@ async function installIntoHost(input, hostLabel) {
|
|
|
8961
9043
|
}
|
|
8962
9044
|
}
|
|
8963
9045
|
previousEntry.enabled = true;
|
|
8964
|
-
await (0,
|
|
9046
|
+
await (0, import_promises5.writeFile)(input.configPath, `${JSON.stringify(config, null, 2)}
|
|
8965
9047
|
`);
|
|
8966
9048
|
return {
|
|
8967
9049
|
configPath: input.configPath,
|
|
@@ -8978,9 +9060,14 @@ async function runInstallCommand(input) {
|
|
|
8978
9060
|
throw new Error("expected subcommand: install");
|
|
8979
9061
|
}
|
|
8980
9062
|
const args = parseArgs(argv.slice(1));
|
|
8981
|
-
const
|
|
8982
|
-
|
|
8983
|
-
|
|
9063
|
+
const destinations = await resolveInstallDestinations(args, {
|
|
9064
|
+
hostDefinitions: input.hostDefinitions,
|
|
9065
|
+
selectHosts: input.selectHosts,
|
|
9066
|
+
selectHost: input.selectHost,
|
|
9067
|
+
ttyPath: input.ttyPath
|
|
9068
|
+
});
|
|
9069
|
+
for (const destination of destinations) {
|
|
9070
|
+
const installInput = {
|
|
8984
9071
|
packageRoot: input.packageRoot,
|
|
8985
9072
|
extensionsDir: destination.extensionsDir,
|
|
8986
9073
|
configPath: destination.configPath,
|
|
@@ -8995,35 +9082,186 @@ async function runInstallCommand(input) {
|
|
|
8995
9082
|
hubEnabled: parseOptionalBoolean(args["hub-enabled"]),
|
|
8996
9083
|
consoleHost: args["console-host"],
|
|
8997
9084
|
consolePort: args["console-port"] ? Number(args["console-port"]) : void 0
|
|
8998
|
-
}
|
|
8999
|
-
"
|
|
9000
|
-
|
|
9001
|
-
|
|
9002
|
-
|
|
9003
|
-
|
|
9004
|
-
|
|
9005
|
-
|
|
9006
|
-
|
|
9007
|
-
|
|
9008
|
-
|
|
9009
|
-
"
|
|
9010
|
-
|
|
9011
|
-
);
|
|
9012
|
-
}
|
|
9013
|
-
function resolveInstallDestination(args) {
|
|
9014
|
-
if (args.target !== void 0) {
|
|
9015
|
-
throw new Error("--target is no longer supported; pass --config-path and --extensions-dir from your Claw host");
|
|
9085
|
+
};
|
|
9086
|
+
const result = destination.installKind === "hermes" ? await installIntoHermes(installInput) : await installIntoHost(installInput, destination.label);
|
|
9087
|
+
process.stdout.write(
|
|
9088
|
+
[
|
|
9089
|
+
`Installed ${PLUGIN_ID} into ${destination.label}.`,
|
|
9090
|
+
`Extensions: ${result.extensionsDir}`,
|
|
9091
|
+
`Config: ${result.configPath}`,
|
|
9092
|
+
...destination.installKind === "hermes" ? [] : [`Gateway: ${result.gatewayBaseUrl}`],
|
|
9093
|
+
`53AIHub: ${result.hub53aiConfigured ? "configured" : "not configured"}`,
|
|
9094
|
+
`Plugin build: ${result.pluginBuild}`,
|
|
9095
|
+
`Restart ${destination.label} to load the plugin.`
|
|
9096
|
+
].join("\n") + "\n"
|
|
9097
|
+
);
|
|
9016
9098
|
}
|
|
9099
|
+
}
|
|
9100
|
+
async function resolveInstallDestinations(args, options = {}) {
|
|
9017
9101
|
const explicitConfigPath = args["config-path"] ? (0, import_node_path6.resolve)(args["config-path"]) : void 0;
|
|
9018
9102
|
const explicitExtensionsDir = args["extensions-dir"] ? (0, import_node_path6.resolve)(args["extensions-dir"]) : void 0;
|
|
9019
|
-
if (
|
|
9020
|
-
|
|
9103
|
+
if (explicitConfigPath && explicitExtensionsDir) {
|
|
9104
|
+
const hermes = isHermesDestination(explicitConfigPath, explicitExtensionsDir);
|
|
9105
|
+
return [{
|
|
9106
|
+
configPath: explicitConfigPath,
|
|
9107
|
+
extensionsDir: hermes ? normalizeHermesPlatformsDir(explicitExtensionsDir) : explicitExtensionsDir,
|
|
9108
|
+
label: hermes ? "Hermes" : "Claw",
|
|
9109
|
+
installKind: hermes ? "hermes" : "openclaw"
|
|
9110
|
+
}];
|
|
9111
|
+
}
|
|
9112
|
+
if (explicitConfigPath || explicitExtensionsDir) {
|
|
9113
|
+
throw new Error("pass --config-path and --extensions-dir together, or omit both to auto-detect Claw");
|
|
9114
|
+
}
|
|
9115
|
+
const detected = detectInstallHosts(options.hostDefinitions ?? getDefaultHostDefinitions());
|
|
9116
|
+
const compatible = detected;
|
|
9117
|
+
const incompatible = [];
|
|
9118
|
+
if (compatible.length === 1) {
|
|
9119
|
+
return [toInstallDestination(compatible[0])];
|
|
9120
|
+
}
|
|
9121
|
+
if (compatible.length > 1) {
|
|
9122
|
+
const selected = options.selectHosts ? await options.selectHosts(compatible, incompatible) : options.selectHost ? [await options.selectHost(compatible)] : await promptForInstallHosts(compatible, incompatible, options.ttyPath ?? "/dev/tty");
|
|
9123
|
+
return validateSelectedHosts(selected, compatible).map(toInstallDestination);
|
|
9124
|
+
}
|
|
9125
|
+
throw new Error(
|
|
9126
|
+
[
|
|
9127
|
+
"could not auto-detect an installed Claw host.",
|
|
9128
|
+
"Pass --config-path and --extensions-dir to install into a specific Claw.",
|
|
9129
|
+
"",
|
|
9130
|
+
"Supported default locations:",
|
|
9131
|
+
...formatHostList(options.hostDefinitions ?? getDefaultHostDefinitions())
|
|
9132
|
+
].join("\n")
|
|
9133
|
+
);
|
|
9134
|
+
}
|
|
9135
|
+
function getDefaultHostDefinitions() {
|
|
9136
|
+
const home = (0, import_node_os2.homedir)();
|
|
9137
|
+
const qclawHome = (0, import_node_path6.resolve)(home, ".qclaw");
|
|
9138
|
+
const openClawHome = (0, import_node_path6.resolve)(home, ".openclaw");
|
|
9139
|
+
const hermesHome = (0, import_node_path6.resolve)(home, ".hermes");
|
|
9140
|
+
return [
|
|
9141
|
+
{
|
|
9142
|
+
id: "qclaw",
|
|
9143
|
+
label: "QClaw",
|
|
9144
|
+
configPath: (0, import_node_path6.join)(qclawHome, "openclaw.json"),
|
|
9145
|
+
extensionsDir: (0, import_node_path6.resolve)(home, "Library/Application Support/QClaw/openclaw/config/extensions")
|
|
9146
|
+
},
|
|
9147
|
+
{
|
|
9148
|
+
id: "openclaw",
|
|
9149
|
+
label: "OpenClaw",
|
|
9150
|
+
configPath: (0, import_node_path6.join)(openClawHome, "openclaw.json"),
|
|
9151
|
+
extensionsDir: (0, import_node_path6.resolve)(openClawHome, "extensions")
|
|
9152
|
+
},
|
|
9153
|
+
{
|
|
9154
|
+
id: "hermes",
|
|
9155
|
+
label: "Hermes",
|
|
9156
|
+
configPath: (0, import_node_path6.join)(hermesHome, "config.yaml"),
|
|
9157
|
+
extensionsDir: (0, import_node_path6.resolve)(hermesHome, "plugins", "platforms"),
|
|
9158
|
+
installKind: "hermes"
|
|
9159
|
+
}
|
|
9160
|
+
];
|
|
9161
|
+
}
|
|
9162
|
+
function detectInstallHosts(hosts) {
|
|
9163
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9164
|
+
return hosts.filter((host) => {
|
|
9165
|
+
const key = `${(0, import_node_path6.resolve)(host.configPath)}\0${(0, import_node_path6.resolve)(host.extensionsDir)}`;
|
|
9166
|
+
if (seen.has(key) || !(0, import_node_fs4.existsSync)(host.configPath)) {
|
|
9167
|
+
return false;
|
|
9168
|
+
}
|
|
9169
|
+
seen.add(key);
|
|
9170
|
+
return true;
|
|
9171
|
+
});
|
|
9172
|
+
}
|
|
9173
|
+
async function promptForInstallHosts(hosts, incompatibleHosts, ttyPath) {
|
|
9174
|
+
let handle;
|
|
9175
|
+
try {
|
|
9176
|
+
handle = await (0, import_promises5.open)(ttyPath, "r+");
|
|
9177
|
+
const input = handle.createReadStream();
|
|
9178
|
+
const output = handle.createWriteStream();
|
|
9179
|
+
const readline = (0, import_promises4.createInterface)({ input, output });
|
|
9180
|
+
try {
|
|
9181
|
+
output.write("Multiple Claw installations were detected.\n");
|
|
9182
|
+
output.write("Choose one or more locations to install claw-control-center:\n");
|
|
9183
|
+
hosts.forEach((host, index) => {
|
|
9184
|
+
output.write(`${index + 1}. ${host.label}
|
|
9185
|
+
`);
|
|
9186
|
+
output.write(` Config: ${host.configPath}
|
|
9187
|
+
`);
|
|
9188
|
+
output.write(` Extensions: ${host.extensionsDir}
|
|
9189
|
+
`);
|
|
9190
|
+
});
|
|
9191
|
+
if (incompatibleHosts.length > 0) {
|
|
9192
|
+
output.write("\nDetected but not installable by this OpenClaw plugin installer:\n");
|
|
9193
|
+
for (const host of incompatibleHosts) {
|
|
9194
|
+
output.write(`- ${host.label}: ${host.incompatibilityReason ?? "incompatible plugin format"}
|
|
9195
|
+
`);
|
|
9196
|
+
}
|
|
9197
|
+
}
|
|
9198
|
+
const answer = await readline.question(`Install location(s) [1-${hosts.length}, comma-separated, or all]: `);
|
|
9199
|
+
const selectedIndexes = parseInstallSelection(answer, hosts.length);
|
|
9200
|
+
if (selectedIndexes.length === 0) {
|
|
9201
|
+
throw new Error(`invalid install location: ${answer}`);
|
|
9202
|
+
}
|
|
9203
|
+
return selectedIndexes.map((index) => hosts[index - 1]);
|
|
9204
|
+
} finally {
|
|
9205
|
+
readline.close();
|
|
9206
|
+
input.destroy();
|
|
9207
|
+
output.end();
|
|
9208
|
+
}
|
|
9209
|
+
} catch (error) {
|
|
9210
|
+
if (error instanceof Error && error.message.startsWith("invalid install location:")) {
|
|
9211
|
+
throw error;
|
|
9212
|
+
}
|
|
9213
|
+
throw new Error(
|
|
9214
|
+
[
|
|
9215
|
+
"multiple Claw installations were detected, but no interactive terminal was available.",
|
|
9216
|
+
"Run the installer again with --config-path and --extensions-dir.",
|
|
9217
|
+
"",
|
|
9218
|
+
"Detected locations:",
|
|
9219
|
+
...formatHostList(hosts)
|
|
9220
|
+
].join("\n")
|
|
9221
|
+
);
|
|
9222
|
+
} finally {
|
|
9223
|
+
await handle?.close().catch(() => void 0);
|
|
9021
9224
|
}
|
|
9225
|
+
}
|
|
9226
|
+
function toInstallDestination(host) {
|
|
9022
9227
|
return {
|
|
9023
|
-
configPath:
|
|
9024
|
-
extensionsDir:
|
|
9228
|
+
configPath: (0, import_node_path6.resolve)(host.configPath),
|
|
9229
|
+
extensionsDir: (0, import_node_path6.resolve)(host.extensionsDir),
|
|
9230
|
+
label: host.label,
|
|
9231
|
+
installKind: host.installKind ?? "openclaw"
|
|
9025
9232
|
};
|
|
9026
9233
|
}
|
|
9234
|
+
function validateSelectedHosts(selected, compatible) {
|
|
9235
|
+
const compatibleIds = new Set(compatible.map((host) => host.id));
|
|
9236
|
+
const invalid = selected.find((host) => !compatibleIds.has(host.id));
|
|
9237
|
+
if (invalid) {
|
|
9238
|
+
throw new Error(`selected host is not installable: ${invalid.label}`);
|
|
9239
|
+
}
|
|
9240
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9241
|
+
return selected.filter((host) => {
|
|
9242
|
+
if (seen.has(host.id)) {
|
|
9243
|
+
return false;
|
|
9244
|
+
}
|
|
9245
|
+
seen.add(host.id);
|
|
9246
|
+
return true;
|
|
9247
|
+
});
|
|
9248
|
+
}
|
|
9249
|
+
function parseInstallSelection(answer, hostCount) {
|
|
9250
|
+
const trimmed = answer.trim().toLowerCase();
|
|
9251
|
+
if (trimmed === "all" || trimmed === "*") {
|
|
9252
|
+
return Array.from({ length: hostCount }, (_, index) => index + 1);
|
|
9253
|
+
}
|
|
9254
|
+
const indexes = trimmed.split(",").map((part) => Number(part.trim())).filter((index) => Number.isInteger(index) && index >= 1 && index <= hostCount);
|
|
9255
|
+
return Array.from(new Set(indexes));
|
|
9256
|
+
}
|
|
9257
|
+
function formatHostList(hosts) {
|
|
9258
|
+
return hosts.flatMap((host) => [
|
|
9259
|
+
`- ${host.label}`,
|
|
9260
|
+
` Config: ${host.configPath}`,
|
|
9261
|
+
` Extensions: ${host.extensionsDir}`,
|
|
9262
|
+
...host.incompatibilityReason ? [` Note: ${host.incompatibilityReason}`] : []
|
|
9263
|
+
]);
|
|
9264
|
+
}
|
|
9027
9265
|
function parseArgs(argv) {
|
|
9028
9266
|
const parsed = {};
|
|
9029
9267
|
for (let index = 0; index < argv.length; index += 1) {
|
|
@@ -9031,12 +9269,19 @@ function parseArgs(argv) {
|
|
|
9031
9269
|
if (!entry.startsWith("--")) {
|
|
9032
9270
|
continue;
|
|
9033
9271
|
}
|
|
9272
|
+
const key = entry.slice(2);
|
|
9273
|
+
if (key === "target") {
|
|
9274
|
+
throw new Error("--target has been removed; omit it to auto-detect Claw or pass --config-path and --extensions-dir");
|
|
9275
|
+
}
|
|
9276
|
+
if (!SUPPORTED_ARGS.has(key)) {
|
|
9277
|
+
throw new Error(`unknown option: --${key}`);
|
|
9278
|
+
}
|
|
9034
9279
|
const next = argv[index + 1];
|
|
9035
9280
|
if (next && !next.startsWith("--")) {
|
|
9036
|
-
parsed[
|
|
9281
|
+
parsed[key] = next;
|
|
9037
9282
|
index += 1;
|
|
9038
9283
|
} else {
|
|
9039
|
-
parsed[
|
|
9284
|
+
parsed[key] = "true";
|
|
9040
9285
|
}
|
|
9041
9286
|
}
|
|
9042
9287
|
return parsed;
|
|
@@ -9051,16 +9296,25 @@ async function copyPublishablePackage(packageRoot, destination) {
|
|
|
9051
9296
|
continue;
|
|
9052
9297
|
}
|
|
9053
9298
|
const target = (0, import_node_path6.join)(destination, relativePath);
|
|
9054
|
-
await (0,
|
|
9055
|
-
await (0,
|
|
9299
|
+
await (0, import_promises5.rm)(target, { recursive: true, force: true });
|
|
9300
|
+
await (0, import_promises5.cp)(source, target, { recursive: true, force: true });
|
|
9056
9301
|
}
|
|
9057
9302
|
}
|
|
9303
|
+
async function copyHermesPlatformPackage(packageRoot, destination) {
|
|
9304
|
+
const source = (0, import_node_path6.join)(packageRoot, "hermes", "platforms", HERMES_PLATFORM_ID);
|
|
9305
|
+
if (!(0, import_node_fs4.existsSync)(source)) {
|
|
9306
|
+
throw new Error(`Hermes platform package does not exist: ${source}`);
|
|
9307
|
+
}
|
|
9308
|
+
await (0, import_promises5.rm)(destination, { recursive: true, force: true });
|
|
9309
|
+
await (0, import_promises5.mkdir)((0, import_node_path6.dirname)(destination), { recursive: true });
|
|
9310
|
+
await (0, import_promises5.cp)(source, destination, { recursive: true, force: true });
|
|
9311
|
+
}
|
|
9058
9312
|
async function readPluginBuildInfo(destination) {
|
|
9059
9313
|
const packagePath = (0, import_node_path6.join)(destination, "package.json");
|
|
9060
9314
|
const entryPath = (0, import_node_path6.join)(destination, "dist", "index.cjs");
|
|
9061
9315
|
let version = "unknown";
|
|
9062
9316
|
try {
|
|
9063
|
-
const packageJson = JSON.parse(await (0,
|
|
9317
|
+
const packageJson = JSON.parse(await (0, import_promises5.readFile)(packagePath, "utf8"));
|
|
9064
9318
|
if (typeof packageJson.version === "string" && packageJson.version.trim()) {
|
|
9065
9319
|
version = packageJson.version.trim();
|
|
9066
9320
|
}
|
|
@@ -9068,18 +9322,92 @@ async function readPluginBuildInfo(destination) {
|
|
|
9068
9322
|
version = "unknown";
|
|
9069
9323
|
}
|
|
9070
9324
|
try {
|
|
9071
|
-
const entry = await (0,
|
|
9325
|
+
const entry = await (0, import_promises5.readFile)(entryPath);
|
|
9072
9326
|
const digest = (0, import_node_crypto4.createHash)("sha256").update(entry).digest("hex").slice(0, 12);
|
|
9073
9327
|
return `${PLUGIN_ID}@${version} sha256:${digest}`;
|
|
9074
9328
|
} catch {
|
|
9075
9329
|
return `${PLUGIN_ID}@${version} sha256:missing`;
|
|
9076
9330
|
}
|
|
9077
9331
|
}
|
|
9332
|
+
async function readHermesPluginBuildInfo(destination) {
|
|
9333
|
+
const manifestPath = (0, import_node_path6.join)(destination, "plugin.yaml");
|
|
9334
|
+
try {
|
|
9335
|
+
const manifest = (0, import_yaml.parse)(await (0, import_promises5.readFile)(manifestPath, "utf8"));
|
|
9336
|
+
const version = typeof manifest?.version === "string" || typeof manifest?.version === "number" ? String(manifest.version) : "unknown";
|
|
9337
|
+
const adapter = await (0, import_promises5.readFile)((0, import_node_path6.join)(destination, "adapter.py"));
|
|
9338
|
+
const digest = (0, import_node_crypto4.createHash)("sha256").update(adapter).digest("hex").slice(0, 12);
|
|
9339
|
+
return `${PLUGIN_ID}/hermes@${version} sha256:${digest}`;
|
|
9340
|
+
} catch {
|
|
9341
|
+
return `${PLUGIN_ID}/hermes@unknown sha256:missing`;
|
|
9342
|
+
}
|
|
9343
|
+
}
|
|
9078
9344
|
async function readOpenClawConfig(configPath) {
|
|
9079
9345
|
if (!(0, import_node_fs4.existsSync)(configPath)) {
|
|
9080
9346
|
return {};
|
|
9081
9347
|
}
|
|
9082
|
-
return JSON.parse(await (0,
|
|
9348
|
+
return JSON.parse(await (0, import_promises5.readFile)(configPath, "utf8"));
|
|
9349
|
+
}
|
|
9350
|
+
async function updateHermesConfig(configPath) {
|
|
9351
|
+
await (0, import_promises5.mkdir)((0, import_node_path6.dirname)(configPath), { recursive: true });
|
|
9352
|
+
const config = await readHermesConfig(configPath);
|
|
9353
|
+
const plugins = ensureObject(config, "plugins");
|
|
9354
|
+
plugins.enabled = dedupeStrings([...Array.isArray(plugins.enabled) ? plugins.enabled : [], HERMES_PLUGIN_KEY, HERMES_PLATFORM_ID]);
|
|
9355
|
+
const platforms = ensureObject(config, "platforms");
|
|
9356
|
+
const platform = ensureObject(platforms, HERMES_PLATFORM_ID);
|
|
9357
|
+
platform.enabled = true;
|
|
9358
|
+
ensureObject(platform, "extra");
|
|
9359
|
+
await (0, import_promises5.writeFile)(configPath, (0, import_yaml.stringify)(config));
|
|
9360
|
+
}
|
|
9361
|
+
async function readHermesConfig(configPath) {
|
|
9362
|
+
if (!(0, import_node_fs4.existsSync)(configPath)) {
|
|
9363
|
+
return {};
|
|
9364
|
+
}
|
|
9365
|
+
const parsed = (0, import_yaml.parse)(await (0, import_promises5.readFile)(configPath, "utf8"));
|
|
9366
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
9367
|
+
}
|
|
9368
|
+
async function updateHermesEnv(configPath, values) {
|
|
9369
|
+
const envPath = (0, import_node_path6.join)((0, import_node_path6.dirname)(configPath), ".env");
|
|
9370
|
+
await (0, import_promises5.mkdir)((0, import_node_path6.dirname)(envPath), { recursive: true });
|
|
9371
|
+
const existing = (0, import_node_fs4.existsSync)(envPath) ? await (0, import_promises5.readFile)(envPath, "utf8") : "";
|
|
9372
|
+
const updates = /* @__PURE__ */ new Map([
|
|
9373
|
+
[HERMES_ENV_KEYS.botId, values.botId],
|
|
9374
|
+
[HERMES_ENV_KEYS.secret, values.secret],
|
|
9375
|
+
[HERMES_ENV_KEYS.wsUrl, values.wsUrl]
|
|
9376
|
+
]);
|
|
9377
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9378
|
+
const lines = existing.split(/\r?\n/).map((line) => {
|
|
9379
|
+
const match = line.match(/^([A-Za-z_][A-Za-z0-9_]*)=/);
|
|
9380
|
+
if (!match || !updates.has(match[1])) {
|
|
9381
|
+
return line;
|
|
9382
|
+
}
|
|
9383
|
+
const key = match[1];
|
|
9384
|
+
seen.add(key);
|
|
9385
|
+
return `${key}=${quoteEnvValue(updates.get(key))}`;
|
|
9386
|
+
});
|
|
9387
|
+
for (const [key, value] of updates) {
|
|
9388
|
+
if (!seen.has(key)) {
|
|
9389
|
+
lines.push(`${key}=${quoteEnvValue(value)}`);
|
|
9390
|
+
}
|
|
9391
|
+
}
|
|
9392
|
+
await (0, import_promises5.writeFile)(envPath, `${lines.filter((line, index, all) => line || index < all.length - 1).join("\n")}
|
|
9393
|
+
`);
|
|
9394
|
+
}
|
|
9395
|
+
function quoteEnvValue(value) {
|
|
9396
|
+
return JSON.stringify(value);
|
|
9397
|
+
}
|
|
9398
|
+
function isHermesDestination(configPath, extensionsDir) {
|
|
9399
|
+
const tail = extensionsDir.split(/[\\/]/).filter(Boolean).slice(-2).join("/");
|
|
9400
|
+
return configPath.endsWith("config.yaml") && (tail === "plugins/platforms" || tail.endsWith("/plugins"));
|
|
9401
|
+
}
|
|
9402
|
+
function normalizeHermesPlatformsDir(extensionsDir) {
|
|
9403
|
+
const parts = extensionsDir.split(/[\\/]/).filter(Boolean);
|
|
9404
|
+
if (parts.at(-1) === "platforms" && parts.at(-2) === "plugins") {
|
|
9405
|
+
return extensionsDir;
|
|
9406
|
+
}
|
|
9407
|
+
if (parts.at(-1) === "plugins") {
|
|
9408
|
+
return (0, import_node_path6.join)(extensionsDir, "platforms");
|
|
9409
|
+
}
|
|
9410
|
+
return extensionsDir;
|
|
9083
9411
|
}
|
|
9084
9412
|
function inferGatewaySettings(config) {
|
|
9085
9413
|
const gateway = config.gateway ?? {};
|