theclawbay 0.3.75 → 0.3.77
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 +2 -2
- package/dist/commands/logout.js +117 -0
- package/dist/commands/setup.js +143 -6
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# theclawbay
|
|
2
2
|
|
|
3
|
-
CLI for connecting Codex, Continue, Cline, OpenClaw, OpenCode, Kilo, Roo Code, Aider, experimental Trae, and experimental Zo to The Claw Bay.
|
|
3
|
+
CLI for connecting Codex, Hermes Agent, Continue, Cline, OpenClaw, OpenCode, Kilo, Roo Code, Aider, experimental Trae, and experimental Zo to The Claw Bay.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -16,7 +16,7 @@ Get your API key from `https://theclawbay.com/dashboard`.
|
|
|
16
16
|
theclawbay setup --api-key <apiKey>
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
In an interactive terminal, setup shows one picker for Codex, Continue, Cline, OpenClaw, OpenCode, Kilo, Roo Code, Aider, Windows Trae, and Zo.
|
|
19
|
+
In an interactive terminal, setup shows one picker for Codex, Hermes Agent, Continue, Cline, OpenClaw, OpenCode, Kilo, Roo Code, Aider, Windows Trae, and Zo.
|
|
20
20
|
Each row includes a terminal-friendly icon plus the tool's official site, and you can toggle items with arrow keys plus `Enter` or by pressing `1-9` and `0`.
|
|
21
21
|
Re-running setup also migrates legacy OpenCode and Kilo patches to the current reasoning-capable provider path and refreshes OpenClaw model metadata.
|
|
22
22
|
|
package/dist/commands/logout.js
CHANGED
|
@@ -71,6 +71,8 @@ const THECLAWBAY_CANONICAL_API_HOST = "api.theclawbay.com";
|
|
|
71
71
|
const THECLAWBAY_WEBSITE_HOSTS = new Set(["theclawbay.com", "www.theclawbay.com"]);
|
|
72
72
|
const SUPPORTED_MODEL_IDS = new Set((0, supported_models_1.getSupportedModelIds)());
|
|
73
73
|
const CONTINUE_MODEL_NAME = "The Claw Bay";
|
|
74
|
+
const HERMES_PROVIDER_NAME = "The Claw Bay";
|
|
75
|
+
const HERMES_KEY_ENV_NAME = "HERMES_THECLAWBAY_API_KEY";
|
|
74
76
|
const TRAE_PATCH_MARKER = "theclawbay-trae-patch";
|
|
75
77
|
const TRAE_BUNDLE_BACKUP_SUFFIX = ".theclawbay-managed-backup";
|
|
76
78
|
const MANAGED_EDITOR_TERMINAL_ENV_NAMES = [
|
|
@@ -272,6 +274,36 @@ async function readFileIfExists(filePath) {
|
|
|
272
274
|
throw error;
|
|
273
275
|
}
|
|
274
276
|
}
|
|
277
|
+
function hermesHomeDir() {
|
|
278
|
+
const raw = process.env.HERMES_HOME?.trim();
|
|
279
|
+
if (raw)
|
|
280
|
+
return raw;
|
|
281
|
+
return node_path_1.default.join(node_os_1.default.homedir(), ".hermes");
|
|
282
|
+
}
|
|
283
|
+
function hermesConfigPath() {
|
|
284
|
+
return node_path_1.default.join(hermesHomeDir(), "config.yaml");
|
|
285
|
+
}
|
|
286
|
+
function hermesEnvPath() {
|
|
287
|
+
return node_path_1.default.join(hermesHomeDir(), ".env");
|
|
288
|
+
}
|
|
289
|
+
async function removeDotEnvValue(filePath, key) {
|
|
290
|
+
const existing = await readFileIfExists(filePath);
|
|
291
|
+
if (existing === null)
|
|
292
|
+
return false;
|
|
293
|
+
const nextLines = existing
|
|
294
|
+
.split(/\r?\n/)
|
|
295
|
+
.filter((line) => !new RegExp(`^\\s*${key}\\s*=`).test(line));
|
|
296
|
+
const next = `${nextLines.join("\n").trimEnd()}\n`;
|
|
297
|
+
const normalizedExisting = `${existing.trimEnd()}\n`;
|
|
298
|
+
if (next === normalizedExisting)
|
|
299
|
+
return false;
|
|
300
|
+
if (!next.trim()) {
|
|
301
|
+
return removeFileIfExists(filePath);
|
|
302
|
+
}
|
|
303
|
+
await promises_1.default.mkdir(node_path_1.default.dirname(filePath), { recursive: true });
|
|
304
|
+
await promises_1.default.writeFile(filePath, next, "utf8");
|
|
305
|
+
return true;
|
|
306
|
+
}
|
|
275
307
|
function localAppDataDir() {
|
|
276
308
|
if (process.env.LOCALAPPDATA?.trim())
|
|
277
309
|
return process.env.LOCALAPPDATA;
|
|
@@ -1308,6 +1340,85 @@ async function cleanupKiloConfig() {
|
|
|
1308
1340
|
restoreStatePath: KILO_RESTORE_STATE_PATH,
|
|
1309
1341
|
});
|
|
1310
1342
|
}
|
|
1343
|
+
async function cleanupHermesConfig() {
|
|
1344
|
+
const configPath = hermesConfigPath();
|
|
1345
|
+
const envPath = hermesEnvPath();
|
|
1346
|
+
const existingRaw = await readFileIfExists(configPath);
|
|
1347
|
+
let configChanged = false;
|
|
1348
|
+
let removedManagedProvider = false;
|
|
1349
|
+
const removedProviderBaseUrls = new Set();
|
|
1350
|
+
if (existingRaw !== null && existingRaw.trim()) {
|
|
1351
|
+
try {
|
|
1352
|
+
const existingConfig = objectRecordOr((0, yaml_1.parseDocument)(existingRaw).toJS(), {});
|
|
1353
|
+
const nextConfig = { ...existingConfig };
|
|
1354
|
+
const rawCustomProviders = Array.isArray(existingConfig.custom_providers)
|
|
1355
|
+
? existingConfig.custom_providers
|
|
1356
|
+
: [];
|
|
1357
|
+
const nextCustomProviders = rawCustomProviders.filter((entry) => {
|
|
1358
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry))
|
|
1359
|
+
return true;
|
|
1360
|
+
const record = entry;
|
|
1361
|
+
const name = typeof record.name === "string" ? record.name.trim() : "";
|
|
1362
|
+
const providerBaseUrl = typeof record.base_url === "string" ? record.base_url.trim().replace(/\/+$/g, "") : "";
|
|
1363
|
+
const keyEnv = typeof record.key_env === "string" ? record.key_env.trim() : "";
|
|
1364
|
+
if (keyEnv === HERMES_KEY_ENV_NAME) {
|
|
1365
|
+
removedManagedProvider = true;
|
|
1366
|
+
if (providerBaseUrl)
|
|
1367
|
+
removedProviderBaseUrls.add(providerBaseUrl);
|
|
1368
|
+
return false;
|
|
1369
|
+
}
|
|
1370
|
+
if (name === HERMES_PROVIDER_NAME && isTheClawBayOpenAiCompatibleBaseUrl(providerBaseUrl)) {
|
|
1371
|
+
removedManagedProvider = true;
|
|
1372
|
+
if (providerBaseUrl)
|
|
1373
|
+
removedProviderBaseUrls.add(providerBaseUrl);
|
|
1374
|
+
return false;
|
|
1375
|
+
}
|
|
1376
|
+
return true;
|
|
1377
|
+
});
|
|
1378
|
+
if (nextCustomProviders.length !== rawCustomProviders.length) {
|
|
1379
|
+
configChanged = true;
|
|
1380
|
+
}
|
|
1381
|
+
if (nextCustomProviders.length > 0) {
|
|
1382
|
+
nextConfig.custom_providers = nextCustomProviders;
|
|
1383
|
+
}
|
|
1384
|
+
else if ("custom_providers" in nextConfig) {
|
|
1385
|
+
delete nextConfig.custom_providers;
|
|
1386
|
+
configChanged = true;
|
|
1387
|
+
}
|
|
1388
|
+
const modelConfig = objectRecordOr(existingConfig.model, {});
|
|
1389
|
+
const provider = typeof modelConfig.provider === "string" ? modelConfig.provider.trim() : "";
|
|
1390
|
+
const baseUrl = typeof modelConfig.base_url === "string" ? modelConfig.base_url.trim().replace(/\/+$/g, "") : "";
|
|
1391
|
+
const apiMode = typeof modelConfig.api_mode === "string" ? modelConfig.api_mode.trim() : "";
|
|
1392
|
+
const shouldRemoveManagedModel = provider === "custom" &&
|
|
1393
|
+
(isTheClawBayOpenAiCompatibleBaseUrl(baseUrl) ||
|
|
1394
|
+
(removedManagedProvider && apiMode === "codex_responses" && removedProviderBaseUrls.has(baseUrl)));
|
|
1395
|
+
if (shouldRemoveManagedModel) {
|
|
1396
|
+
for (const key of ["provider", "default", "base_url", "api_mode", "api_key", "context_length"]) {
|
|
1397
|
+
if (key in modelConfig) {
|
|
1398
|
+
delete modelConfig[key];
|
|
1399
|
+
configChanged = true;
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
if (Object.keys(modelConfig).length > 0) {
|
|
1403
|
+
nextConfig.model = modelConfig;
|
|
1404
|
+
}
|
|
1405
|
+
else if ("model" in nextConfig) {
|
|
1406
|
+
delete nextConfig.model;
|
|
1407
|
+
configChanged = true;
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
if (configChanged) {
|
|
1411
|
+
await promises_1.default.mkdir(node_path_1.default.dirname(configPath), { recursive: true });
|
|
1412
|
+
await promises_1.default.writeFile(configPath, (0, yaml_1.stringify)(nextConfig), "utf8");
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
catch {
|
|
1416
|
+
// Leave invalid user config untouched; still remove our dedicated env key below.
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
const envChanged = await removeDotEnvValue(envPath, HERMES_KEY_ENV_NAME);
|
|
1420
|
+
return configChanged || envChanged;
|
|
1421
|
+
}
|
|
1311
1422
|
async function cleanupTraeBundle() {
|
|
1312
1423
|
const bundlePath = traeBundlePath();
|
|
1313
1424
|
if (!bundlePath)
|
|
@@ -1359,6 +1470,7 @@ class LogoutCommand extends base_command_1.BaseCommand {
|
|
|
1359
1470
|
let updatedOpenCodeConfig = false;
|
|
1360
1471
|
let updatedKiloConfig = false;
|
|
1361
1472
|
let updatedRooConfig = false;
|
|
1473
|
+
let updatedHermesConfig = false;
|
|
1362
1474
|
let updatedTraeBundle = false;
|
|
1363
1475
|
let updatedAiderConfig = false;
|
|
1364
1476
|
let sessionMigration;
|
|
@@ -1436,6 +1548,8 @@ class LogoutCommand extends base_command_1.BaseCommand {
|
|
|
1436
1548
|
updatedKiloConfig = await cleanupKiloConfig();
|
|
1437
1549
|
progress.update("Reverting Roo Code");
|
|
1438
1550
|
updatedRooConfig = await cleanupRooConfig();
|
|
1551
|
+
progress.update("Reverting Hermes");
|
|
1552
|
+
updatedHermesConfig = await cleanupHermesConfig();
|
|
1439
1553
|
progress.update("Reverting Trae");
|
|
1440
1554
|
updatedTraeBundle = await cleanupTraeBundle();
|
|
1441
1555
|
progress.update("Reverting Aider");
|
|
@@ -1491,6 +1605,8 @@ class LogoutCommand extends base_command_1.BaseCommand {
|
|
|
1491
1605
|
revertedTargets.push("Kilo Code");
|
|
1492
1606
|
if (updatedRooConfig)
|
|
1493
1607
|
revertedTargets.push("Roo Code");
|
|
1608
|
+
if (updatedHermesConfig)
|
|
1609
|
+
revertedTargets.push("Hermes");
|
|
1494
1610
|
if (updatedTraeBundle)
|
|
1495
1611
|
revertedTargets.push("Trae");
|
|
1496
1612
|
if (updatedAiderConfig)
|
|
@@ -1595,6 +1711,7 @@ class LogoutCommand extends base_command_1.BaseCommand {
|
|
|
1595
1711
|
this.log(`- OpenCode config cleaned: ${updatedOpenCodeConfig ? "yes" : "no"}`);
|
|
1596
1712
|
this.log(`- Kilo config cleaned: ${updatedKiloConfig ? "yes" : "no"}`);
|
|
1597
1713
|
this.log(`- Roo Code setup hook cleaned: ${updatedRooConfig ? "yes" : "no"}`);
|
|
1714
|
+
this.log(`- Hermes config cleaned: ${updatedHermesConfig ? "yes" : "no"}`);
|
|
1598
1715
|
this.log(`- Trae experimental patch cleaned: ${updatedTraeBundle ? "yes" : "no"}`);
|
|
1599
1716
|
this.log(`- Aider config cleaned: ${updatedAiderConfig ? "yes" : "no"}`);
|
|
1600
1717
|
this.log("Note: restart terminals/VS Code windows to clear already-loaded shell environment.");
|
package/dist/commands/setup.js
CHANGED
|
@@ -36,6 +36,7 @@ const DEFAULT_ROO_MODEL = DEFAULT_CODEX_MODEL;
|
|
|
36
36
|
const DEFAULT_TRAE_MODEL = DEFAULT_CODEX_MODEL;
|
|
37
37
|
const DEFAULT_AIDER_MODEL = DEFAULT_CODEX_MODEL;
|
|
38
38
|
const DEFAULT_ZO_MODEL = DEFAULT_CODEX_MODEL;
|
|
39
|
+
const DEFAULT_HERMES_MODEL = DEFAULT_CODEX_MODEL;
|
|
39
40
|
const DEFAULT_MODELS = [...SUPPORTED_MODEL_IDS];
|
|
40
41
|
const PREFERRED_MODELS = [...SUPPORTED_MODEL_IDS];
|
|
41
42
|
const ENV_KEY_NAME = "THECLAWBAY_API_KEY";
|
|
@@ -92,7 +93,7 @@ const SHELL_END = "# theclawbay-shell-managed:end";
|
|
|
92
93
|
const OPENCLAW_PROVIDER_ID = DEFAULT_PROVIDER_ID;
|
|
93
94
|
const HISTORY_PROVIDER_NEUTRALIZE_SOURCES = new Set(["openai", "theclawbay-wan", DEFAULT_PROVIDER_ID]);
|
|
94
95
|
const HISTORY_PROVIDER_DB_MIGRATE_SOURCES = ["openai", DEFAULT_PROVIDER_ID, "theclawbay-wan"];
|
|
95
|
-
const SETUP_CLIENT_IDS = ["codex", "claude", "continue", "cline", "gsd", "openclaw", "opencode", "kilo", "roo", "trae", "aider", "zo"];
|
|
96
|
+
const SETUP_CLIENT_IDS = ["codex", "claude", "continue", "cline", "gsd", "openclaw", "opencode", "kilo", "roo", "trae", "aider", "zo", "hermes"];
|
|
96
97
|
const LEGACY_THECLAWBAY_OPENAI_PROXY_SUFFIX = "/api/codex-auth/v1/proxy/v1";
|
|
97
98
|
const CANONICAL_THECLAWBAY_OPENAI_PROXY_SUFFIX = "/v1";
|
|
98
99
|
const CANONICAL_CODEX_NATIVE_PROXY_SUFFIX = "/backend-api/codex";
|
|
@@ -113,6 +114,8 @@ const ZO_CONFIG_NAME_PREFIX = "The Claw Bay";
|
|
|
113
114
|
const ZO_COOKIE_HOST = ".zo.computer";
|
|
114
115
|
const ZO_ACCESS_TOKEN_COOKIE = "access_token";
|
|
115
116
|
const ZO_API_BASE_URL = "https://api.zo.computer";
|
|
117
|
+
const HERMES_PROVIDER_NAME = "The Claw Bay";
|
|
118
|
+
const HERMES_KEY_ENV_NAME = "HERMES_THECLAWBAY_API_KEY";
|
|
116
119
|
function trimTrailingSlash(value) {
|
|
117
120
|
return value.replace(/\/+$/g, "");
|
|
118
121
|
}
|
|
@@ -1511,6 +1514,111 @@ async function detectZoClient() {
|
|
|
1511
1514
|
}
|
|
1512
1515
|
return false;
|
|
1513
1516
|
}
|
|
1517
|
+
function hermesHomeDir() {
|
|
1518
|
+
const raw = process.env.HERMES_HOME?.trim();
|
|
1519
|
+
if (raw)
|
|
1520
|
+
return raw;
|
|
1521
|
+
return node_path_1.default.join(node_os_1.default.homedir(), ".hermes");
|
|
1522
|
+
}
|
|
1523
|
+
function hermesConfigPath() {
|
|
1524
|
+
return node_path_1.default.join(hermesHomeDir(), "config.yaml");
|
|
1525
|
+
}
|
|
1526
|
+
function hermesEnvPath() {
|
|
1527
|
+
return node_path_1.default.join(hermesHomeDir(), ".env");
|
|
1528
|
+
}
|
|
1529
|
+
async function detectHermesClient() {
|
|
1530
|
+
if (hasCommand("hermes"))
|
|
1531
|
+
return true;
|
|
1532
|
+
const candidates = [
|
|
1533
|
+
hermesHomeDir(),
|
|
1534
|
+
hermesConfigPath(),
|
|
1535
|
+
hermesEnvPath(),
|
|
1536
|
+
];
|
|
1537
|
+
for (const candidate of candidates) {
|
|
1538
|
+
if (await pathExists(candidate))
|
|
1539
|
+
return true;
|
|
1540
|
+
}
|
|
1541
|
+
return false;
|
|
1542
|
+
}
|
|
1543
|
+
function formatDotEnvValue(value) {
|
|
1544
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
1545
|
+
}
|
|
1546
|
+
async function upsertDotEnvValue(filePath, key, value) {
|
|
1547
|
+
const existing = (await readFileIfExists(filePath)) ?? "";
|
|
1548
|
+
const lines = existing ? existing.split(/\r?\n/) : [];
|
|
1549
|
+
const assignment = `${key}=${formatDotEnvValue(value)}`;
|
|
1550
|
+
let changed = false;
|
|
1551
|
+
let replaced = false;
|
|
1552
|
+
const nextLines = lines.map((line) => {
|
|
1553
|
+
if (new RegExp(`^\\s*${key}\\s*=`).test(line)) {
|
|
1554
|
+
replaced = true;
|
|
1555
|
+
if (line === assignment)
|
|
1556
|
+
return line;
|
|
1557
|
+
changed = true;
|
|
1558
|
+
return assignment;
|
|
1559
|
+
}
|
|
1560
|
+
return line;
|
|
1561
|
+
});
|
|
1562
|
+
if (!replaced) {
|
|
1563
|
+
if (nextLines.length > 0 && nextLines[nextLines.length - 1]?.trim()) {
|
|
1564
|
+
nextLines.push("");
|
|
1565
|
+
}
|
|
1566
|
+
nextLines.push(assignment);
|
|
1567
|
+
changed = true;
|
|
1568
|
+
}
|
|
1569
|
+
if (!changed)
|
|
1570
|
+
return false;
|
|
1571
|
+
await promises_1.default.mkdir(node_path_1.default.dirname(filePath), { recursive: true });
|
|
1572
|
+
await promises_1.default.writeFile(filePath, `${nextLines.join("\n").trimEnd()}\n`, "utf8");
|
|
1573
|
+
return true;
|
|
1574
|
+
}
|
|
1575
|
+
async function writeHermesConfig(params) {
|
|
1576
|
+
const configPath = hermesConfigPath();
|
|
1577
|
+
const envPath = hermesEnvPath();
|
|
1578
|
+
const baseUrl = openAiCompatibleProxyUrl(params.backendUrl);
|
|
1579
|
+
const selectedModel = params.model.trim() || DEFAULT_HERMES_MODEL;
|
|
1580
|
+
const existingRaw = await readFileIfExists(configPath);
|
|
1581
|
+
const existingConfig = existingRaw?.trim()
|
|
1582
|
+
? objectRecordOr((0, yaml_1.parseDocument)(existingRaw).toJS(), {})
|
|
1583
|
+
: {};
|
|
1584
|
+
const nextConfig = { ...existingConfig };
|
|
1585
|
+
const modelConfig = objectRecordOr(existingConfig.model, {});
|
|
1586
|
+
modelConfig.provider = "custom";
|
|
1587
|
+
modelConfig.default = selectedModel;
|
|
1588
|
+
modelConfig.base_url = baseUrl;
|
|
1589
|
+
modelConfig.api_mode = "codex_responses";
|
|
1590
|
+
delete modelConfig.api_key;
|
|
1591
|
+
delete modelConfig.context_length;
|
|
1592
|
+
nextConfig.model = modelConfig;
|
|
1593
|
+
const rawCustomProviders = Array.isArray(existingConfig.custom_providers)
|
|
1594
|
+
? existingConfig.custom_providers
|
|
1595
|
+
: [];
|
|
1596
|
+
const nextCustomProviders = rawCustomProviders.filter((entry) => {
|
|
1597
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry))
|
|
1598
|
+
return true;
|
|
1599
|
+
const record = entry;
|
|
1600
|
+
const name = typeof record.name === "string" ? record.name.trim() : "";
|
|
1601
|
+
const providerBaseUrl = typeof record.base_url === "string" ? record.base_url.trim() : "";
|
|
1602
|
+
const keyEnv = typeof record.key_env === "string" ? record.key_env.trim() : "";
|
|
1603
|
+
if (keyEnv === HERMES_KEY_ENV_NAME)
|
|
1604
|
+
return false;
|
|
1605
|
+
if (name === HERMES_PROVIDER_NAME && providerBaseUrl === baseUrl)
|
|
1606
|
+
return false;
|
|
1607
|
+
return true;
|
|
1608
|
+
});
|
|
1609
|
+
nextCustomProviders.push({
|
|
1610
|
+
name: HERMES_PROVIDER_NAME,
|
|
1611
|
+
base_url: baseUrl,
|
|
1612
|
+
key_env: HERMES_KEY_ENV_NAME,
|
|
1613
|
+
model: selectedModel,
|
|
1614
|
+
api_mode: "codex_responses",
|
|
1615
|
+
});
|
|
1616
|
+
nextConfig.custom_providers = nextCustomProviders;
|
|
1617
|
+
await promises_1.default.mkdir(node_path_1.default.dirname(configPath), { recursive: true });
|
|
1618
|
+
await promises_1.default.writeFile(configPath, (0, yaml_1.stringify)(nextConfig), "utf8");
|
|
1619
|
+
await upsertDotEnvValue(envPath, HERMES_KEY_ENV_NAME, params.apiKey);
|
|
1620
|
+
return [configPath, envPath];
|
|
1621
|
+
}
|
|
1514
1622
|
async function resolveModels(backendUrl, apiKey) {
|
|
1515
1623
|
const { ids, failure } = await fetchBackendModelIds(backendUrl, apiKey);
|
|
1516
1624
|
const available = new Set(ids ?? []);
|
|
@@ -1594,9 +1702,6 @@ async function writeCodexConfig(params) {
|
|
|
1594
1702
|
next = removeTopLevelKeyLineIf(next, "chatgpt_base_url", isTheClawBayChatgptBaseUrl);
|
|
1595
1703
|
const managedBlock = appendManagedBlock("", [
|
|
1596
1704
|
MANAGED_START,
|
|
1597
|
-
`[plugins."computer-use@openai-bundled"]`,
|
|
1598
|
-
"enabled = true",
|
|
1599
|
-
"",
|
|
1600
1705
|
`[model_providers.${DEFAULT_PROVIDER_ID}]`,
|
|
1601
1706
|
'name = "The Claw Bay (OpenAI compatible)"',
|
|
1602
1707
|
`base_url = "${nativeCodexBaseUrl}"`,
|
|
@@ -2895,7 +3000,7 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2895
3000
|
managed?.backendUrl ??
|
|
2896
3001
|
DEFAULT_BACKEND_URL;
|
|
2897
3002
|
const backendUrl = normalizeUrl(backendRaw, "--backend");
|
|
2898
|
-
const [codexDetected, claudeDetected, continueDetected, clineDetected, gsdDetected, openCodeDetected, kiloDetected, rooDetected, traeDetected, aiderDetected, zoDetected] = await Promise.all([
|
|
3003
|
+
const [codexDetected, claudeDetected, continueDetected, clineDetected, gsdDetected, openCodeDetected, kiloDetected, rooDetected, traeDetected, aiderDetected, zoDetected, hermesDetected] = await Promise.all([
|
|
2899
3004
|
detectCodexClient(),
|
|
2900
3005
|
detectClaudeClient(),
|
|
2901
3006
|
detectContinueClient(),
|
|
@@ -2907,6 +3012,7 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2907
3012
|
detectTraeClient(),
|
|
2908
3013
|
detectAiderClient(),
|
|
2909
3014
|
detectZoClient(),
|
|
3015
|
+
detectHermesClient(),
|
|
2910
3016
|
]);
|
|
2911
3017
|
const setupClients = [
|
|
2912
3018
|
{
|
|
@@ -3017,6 +3123,15 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
3017
3123
|
icon: "◉",
|
|
3018
3124
|
siteUrl: "https://www.zo.computer",
|
|
3019
3125
|
},
|
|
3126
|
+
{
|
|
3127
|
+
id: "hermes",
|
|
3128
|
+
label: "Hermes Agent",
|
|
3129
|
+
summaryLabel: "Hermes",
|
|
3130
|
+
detected: hermesDetected,
|
|
3131
|
+
recommended: true,
|
|
3132
|
+
icon: "☿",
|
|
3133
|
+
siteUrl: "https://hermes-agent.nousresearch.com/docs/",
|
|
3134
|
+
},
|
|
3020
3135
|
];
|
|
3021
3136
|
const selectedSetupClients = await resolveSetupClientSelection({
|
|
3022
3137
|
setupClients,
|
|
@@ -3085,6 +3200,7 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
3085
3200
|
let traeBundlePathPatched = null;
|
|
3086
3201
|
let aiderConfigPath = null;
|
|
3087
3202
|
let zoConfigName = null;
|
|
3203
|
+
let hermesConfigPaths = [];
|
|
3088
3204
|
try {
|
|
3089
3205
|
if (selectedSetupClients.size > 0) {
|
|
3090
3206
|
progress.update("Resolving supported models");
|
|
@@ -3275,6 +3391,14 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
3275
3391
|
apiKey: authCredential,
|
|
3276
3392
|
});
|
|
3277
3393
|
}
|
|
3394
|
+
if (selectedSetupClients.has("hermes")) {
|
|
3395
|
+
progress.update("Configuring Hermes Agent");
|
|
3396
|
+
hermesConfigPaths = await writeHermesConfig({
|
|
3397
|
+
backendUrl,
|
|
3398
|
+
model: resolved?.model ?? DEFAULT_HERMES_MODEL,
|
|
3399
|
+
apiKey: authCredential,
|
|
3400
|
+
});
|
|
3401
|
+
}
|
|
3278
3402
|
}
|
|
3279
3403
|
catch (error) {
|
|
3280
3404
|
progress.fail("Setup failed");
|
|
@@ -3305,6 +3429,9 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
3305
3429
|
if (selectedSetupClients.has("zo")) {
|
|
3306
3430
|
summaryNotes.add("Zo uses an experimental account-level BYOK API integration. Keep Zo signed in while running setup.");
|
|
3307
3431
|
}
|
|
3432
|
+
if (selectedSetupClients.has("hermes")) {
|
|
3433
|
+
summaryNotes.add("Hermes Agent: added a named custom provider that uses HERMES_THECLAWBAY_API_KEY, so Hermes can keep its custom-endpoint routing without depending on OPENAI_BASE_URL.");
|
|
3434
|
+
}
|
|
3308
3435
|
if (openClawCliWarning)
|
|
3309
3436
|
summaryNotes.add(openClawCliWarning);
|
|
3310
3437
|
if ((stateDbMigration?.failed.length ?? 0) > 0) {
|
|
@@ -3554,6 +3681,16 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
3554
3681
|
else {
|
|
3555
3682
|
this.log("- Zo: not detected (skipped)");
|
|
3556
3683
|
}
|
|
3684
|
+
if (selectedSetupClients.has("hermes")) {
|
|
3685
|
+
this.log(`- Hermes Agent: configured (${hermesConfigPaths.join(", ")})`);
|
|
3686
|
+
this.log("- Hermes Agent note: saved a named custom provider plus HERMES_THECLAWBAY_API_KEY so Hermes can reuse its custom-provider credential-pool path without relying on OPENAI_BASE_URL.");
|
|
3687
|
+
}
|
|
3688
|
+
else if (hermesDetected) {
|
|
3689
|
+
this.log("- Hermes Agent: detected but skipped");
|
|
3690
|
+
}
|
|
3691
|
+
else {
|
|
3692
|
+
this.log("- Hermes Agent: not detected (skipped)");
|
|
3693
|
+
}
|
|
3557
3694
|
if (selectedSetupClients.has("claude")) {
|
|
3558
3695
|
this.log(`- Claude Code: ${claudeAccess?.enabled ? "configured via shared env" : "selected, but no Claude access was detected for this credential"}`);
|
|
3559
3696
|
}
|
|
@@ -3585,7 +3722,7 @@ SetupCommand.flags = {
|
|
|
3585
3722
|
}),
|
|
3586
3723
|
clients: core_1.Flags.string({
|
|
3587
3724
|
required: false,
|
|
3588
|
-
description: "Detected local clients to configure: codex, claude, continue, cline, gsd, openclaw, opencode, kilo, roo, trae, aider, zo",
|
|
3725
|
+
description: "Detected local clients to configure: codex, claude, continue, cline, gsd, openclaw, opencode, kilo, roo, trae, aider, zo, hermes",
|
|
3589
3726
|
}),
|
|
3590
3727
|
yes: core_1.Flags.boolean({
|
|
3591
3728
|
required: false,
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "theclawbay",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"description": "CLI for connecting Codex, Gemini-compatible apps, Continue, Cline, GSD, OpenClaw, OpenCode, Kilo, Roo Code, Aider, experimental Trae, and experimental Zo to The Claw Bay.",
|
|
3
|
+
"version": "0.3.77",
|
|
4
|
+
"description": "CLI for connecting Codex, Hermes Agent, Gemini-compatible apps, Continue, Cline, GSD, OpenClaw, OpenCode, Kilo, Roo Code, Aider, experimental Trae, and experimental Zo to The Claw Bay.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
|
-
"url": "
|
|
8
|
+
"url": "https://github.com/RCRTCBHAL900/TheClawBay"
|
|
9
9
|
},
|
|
10
10
|
"bin": {
|
|
11
11
|
"theclawbay": "dist/index.js"
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"api-key",
|
|
41
41
|
"continue",
|
|
42
42
|
"cline",
|
|
43
|
+
"hermes",
|
|
43
44
|
"gsd",
|
|
44
45
|
"openclaw",
|
|
45
46
|
"opencode",
|