From 7ef7539575fdebe0d81a1c1894368eaa07a95f93 Mon Sep 17 00:00:00 2001 From: Ashen Date: Fri, 31 Jul 2026 03:56:50 +0530 Subject: [PATCH 1/5] fix: integration configs no longer land in the working directory on Windows --- src/integrations/registry.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/integrations/registry.ts b/src/integrations/registry.ts index 03efe93..b16ac5d 100644 --- a/src/integrations/registry.ts +++ b/src/integrations/registry.ts @@ -6,6 +6,8 @@ import { installOpenClawIntegration } from "./openclaw"; import { installClaudeCodeIntegration } from "./claudecode"; import { installHermesIntegration } from "./hermes"; +const HOME = process.env.HOME || process.env.USERPROFILE || ""; + export interface IntegrationConfig { clientId: string; name: string; @@ -28,27 +30,27 @@ export const CLIENT_CONFIGS: Record = { opencode: { clientId: "opencode", name: "OpenCode", - configPath: join(process.env.HOME || "", ".config/opencode/opencode.json"), + configPath: join(HOME, ".config/opencode/opencode.json"), }, "pi-agent": { clientId: "pi-agent", name: "Pi Agent", - configPath: join(process.env.HOME || "", ".pi/agent/models.json"), + configPath: join(HOME, ".pi/agent/models.json"), }, openclaw: { clientId: "openclaw", name: "OpenClaw", - configPath: join(process.env.HOME || "", ".openclaw/openclaw.json"), + configPath: join(HOME, ".openclaw/openclaw.json"), }, "claude-code": { clientId: "claude-code", name: "Claude Code", - configPath: join(process.env.HOME || "", ".claude/settings.json"), + configPath: join(HOME, ".claude/settings.json"), }, hermes: { clientId: "hermes", name: "Hermes", - configPath: join(process.env.HOME || "", ".hermes/config.yaml"), + configPath: join(HOME, ".hermes/config.yaml"), }, }; From 15ddca86090ae0324a8abd1cf206a397490d935a Mon Sep 17 00:00:00 2001 From: Ashen Date: Fri, 31 Jul 2026 12:35:53 +0530 Subject: [PATCH 2/5] fix: leave the agent config alone when it cannot be loaded --- src/integrations/claudecode.ts | 3 ++- src/integrations/hermes.ts | 3 ++- src/integrations/openclaw.ts | 5 +++-- src/integrations/opencode.ts | 5 +++-- src/integrations/pi.ts | 5 +++-- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/integrations/claudecode.ts b/src/integrations/claudecode.ts index 5b4acf2..66da52a 100644 --- a/src/integrations/claudecode.ts +++ b/src/integrations/claudecode.ts @@ -27,7 +27,8 @@ export async function installClaudeCodeIntegration( settings = JSON.parse(content); } } catch (error) { - console.error(`Error reading ${configPath}, creating new one.`); + console.error(`Failed to read or parse ${configPath}; leaving it unchanged:`, error); + return; } if (!settings.env) { diff --git a/src/integrations/hermes.ts b/src/integrations/hermes.ts index f5f3a28..63706fd 100644 --- a/src/integrations/hermes.ts +++ b/src/integrations/hermes.ts @@ -99,7 +99,8 @@ export async function installHermesIntegration( content = await readFile(configPath, "utf-8"); } } catch (error) { - console.error(`Error reading ${configPath}, creating new one.`); + console.error(`Failed to read ${configPath}; leaving it unchanged:`, error); + return; } let newContent: string; diff --git a/src/integrations/openclaw.ts b/src/integrations/openclaw.ts index c0c1928..9129b88 100644 --- a/src/integrations/openclaw.ts +++ b/src/integrations/openclaw.ts @@ -67,8 +67,9 @@ export async function installOpenClawIntegration( const content = await readFile(configPath, "utf-8"); openclawConfig = JSON.parse(content) as OpenClawConfig; } - } catch { - openclawConfig = {}; + } catch (error) { + console.error(`Failed to read or parse ${configPath}; leaving it unchanged:`, error); + return; } if (!openclawConfig.models) { diff --git a/src/integrations/opencode.ts b/src/integrations/opencode.ts index 56c08f3..2bbdd13 100644 --- a/src/integrations/opencode.ts +++ b/src/integrations/opencode.ts @@ -40,8 +40,9 @@ export async function installOpencodeIntegration( } else { opencodeConfig = { provider: {} }; } - } catch { - opencodeConfig = { provider: {} }; + } catch (error) { + console.error(`Failed to read or parse ${configPath}; leaving it unchanged:`, error); + return; } if (!opencodeConfig.provider) { diff --git a/src/integrations/pi.ts b/src/integrations/pi.ts index ea19385..5715b5f 100644 --- a/src/integrations/pi.ts +++ b/src/integrations/pi.ts @@ -40,8 +40,9 @@ export async function installPiIntegration( const content = await readFile(configPath, "utf-8"); piConfig = JSON.parse(content) as PiConfig; } - } catch { - piConfig = {}; + } catch (error) { + console.error(`Failed to read or parse ${configPath}; leaving it unchanged:`, error); + return; } if (!piConfig.providers) { From e7d9451557bc89af92c2ce334ea08204e086cdd4 Mon Sep 17 00:00:00 2001 From: redshift <213178690+1ftredsh@users.noreply.github.com> Date: Fri, 14 Aug 2026 19:13:26 +0100 Subject: [PATCH 3/5] feat: add 'routstrd local' command to switch back to local daemon mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'routstrd remote ' command sets daemonUrl/authUrl in the config to point at a remote daemon. There was no CLI command to switch back to local mode — users had to manually edit config.json to remove those fields. This adds 'routstrd local' which: - Removes daemonUrl and authUrl from the config file - Preserves all other config (nsec, port, host, etc.) - Shows a clear message about what was removed - Handles the already-local case gracefully --- src/cli.ts | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/cli.ts b/src/cli.ts index 3d4084e..1a39908 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -586,6 +586,39 @@ program } }); +// Local - switch back to local daemon mode (removes daemonUrl/authUrl) +program + .command("local") + .description("Switch back to local daemon mode (removes remote daemon URL)") + .action(async () => { + const config = await loadConfig(); + + if (!config.daemonUrl && !config.authUrl) { + console.log("Already in local mode — no remote daemon URL is configured."); + return; + } + + const previousDaemonUrl = config.daemonUrl; + const previousAuthUrl = config.authUrl; + + const { daemonUrl: _daemonUrl, authUrl: _authUrl, ...rest } = config; + const updatedConfig: RoutstrdConfig = rest; + + await Bun.write(CONFIG_FILE, JSON.stringify(updatedConfig, null, 2)); + + console.log("Switched back to local daemon mode."); + if (previousDaemonUrl) { + console.log(` Removed remote daemon URL: ${previousDaemonUrl}`); + } + if (previousAuthUrl) { + console.log(` Removed auth proxy URL: ${previousAuthUrl}`); + } + console.log( + `\nUse 'routstrd start' to start the local daemon.`, + ); + console.log(`You can view the config file at: ${CONFIG_FILE}`); + }); + // Onboard - initialize the daemon program .command("onboard") From 05a19bec1687ff21350f9d04c9556fd13c665144 Mon Sep 17 00:00:00 2001 From: redshift <213178690+1ftredsh@users.noreply.github.com> Date: Fri, 14 Aug 2026 19:17:50 +0100 Subject: [PATCH 4/5] refactor: base 'already local' guard on daemonUrl only Match the codebase's isRemote check (!!config.daemonUrl). An orphaned authUrl without daemonUrl is already local from the daemon's perspective, so the guard should only check daemonUrl. --- src/cli.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli.ts b/src/cli.ts index 1a39908..aefdc49 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -593,7 +593,7 @@ program .action(async () => { const config = await loadConfig(); - if (!config.daemonUrl && !config.authUrl) { + if (!config.daemonUrl) { console.log("Already in local mode — no remote daemon URL is configured."); return; } From 19b5899bc151261bf9fb0fca085f4af350daedd4 Mon Sep 17 00:00:00 2001 From: redshift <213178690+1ftredsh@users.noreply.github.com> Date: Fri, 14 Aug 2026 19:19:44 +0100 Subject: [PATCH 5/5] docs: clarify next steps message after switching to local mode --- src/cli.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli.ts b/src/cli.ts index aefdc49..6121151 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -614,7 +614,7 @@ program console.log(` Removed auth proxy URL: ${previousAuthUrl}`); } console.log( - `\nUse 'routstrd start' to start the local daemon.`, + `\nUse 'routstrd onboard' for first time using local mode or 'routstrd start' to start the local daemon if you already are using it.`, ); console.log(`You can view the config file at: ${CONFIG_FILE}`); });