fix: distinguish CLI-probe timeouts from not_found, resolve Hermes Agent keyId server-side (#10710+10711) (#10746)

#10710: locateCommand() in cliRuntime.ts collapsed a genuine probe timeout
(runProcess's timedOut flag) into the same reason:"not_found" as a truly
absent binary, on both the where.exe and `command -v` branches. Give
timeouts a distinct "timeout" reason, keep trying remaining command
candidates in locateCommandCandidate instead of treating a timeout as
terminal, and extend the settings-file fallback (cliInstallFallback.ts) to
also cover the new "timeout" reason, matching the scenario it already
existed for.

#10711: the Hermes Agent dashboard "Apply" flow only ever sends `keyId`
(never a raw `apiKey`), but the hermes-agent-settings POST handler never
resolved it, so generateHermesAgentConfig() always fell through to the
literal placeholder "YOUR_OMNIROUTE_API_KEY_HERE" for
providers.omniroute.api_key, delegation.api_key, and every
auxiliary.*.api_key. Resolve keyId server-side via getApiKeyById(), the
same precedented pattern already used by claude-settings/route.ts and
codex-settings/route.ts.

Bug 2 from #10710 (hermes tool-detector configPath) was already fixed by
commit 0a74bfbdea -- confirmed still intact,
no action needed.

Co-authored-by: Markus Hartung <mail@hartmark.se>
This commit is contained in:
Diego Rodrigues de Sa e Souza
2026-08-19 11:08:34 -03:00
committed by GitHub
parent e1c2425ed7
commit 4d92dfe0a2
7 changed files with 367 additions and 9 deletions

View File

@@ -18,11 +18,13 @@ import fsSync from "fs";
* for any CLI tool that declares a `settings` config path (currently
* `claude` and `droid` — see `CLI_TOOLS` in `cliRuntime.ts`).
*
* Only applies when the lookup's own reason is "not_found" — i.e. the binary
* genuinely couldn't be located on PATH/known install paths. Deliberate
* security rejections (unsafe/relative env override paths, symlink escapes,
* suspicious file sizes, etc.) must stay `installed:false` regardless of
* whether a settings file happens to exist.
* Only applies when the lookup's own reason is "not_found" or "timeout" —
* i.e. the binary genuinely couldn't be located on PATH/known install paths,
* or the probe never got a chance to answer (#10710: a probe timeout is one
* more variant of "not currently resolvable", the exact scenario this
* fallback exists for). Deliberate security rejections (unsafe/relative env
* override paths, symlink escapes, suspicious file sizes, etc.) must stay
* `installed:false` regardless of whether a settings file happens to exist.
*/
export interface NotInstalledResult {
installed: false;
@@ -54,7 +56,9 @@ export const withSettingsFallback = (
settingsPath: string | undefined,
notInstalledResult: NotInstalledResult
): NotInstalledResult | SettingsFallbackResult => {
if (notInstalledResult.reason !== "not_found") return notInstalledResult;
if (notInstalledResult.reason !== "not_found" && notInstalledResult.reason !== "timeout") {
return notInstalledResult;
}
if (!settingsPath || !fsSync.existsSync(settingsPath)) return notInstalledResult;
return {