mirror of
https://github.com/Routstr/routstrd.git
synced 2026-10-05 20:38:22 +00:00
Merge pull request #37 from jeroenubbink/fix/onboard-silent-output-and-blocked-postinstall
fix(onboard): show integration menu and progress in terminal
This commit is contained in:
+13
-13
@@ -81,7 +81,7 @@ async function printLightningInvoice(invoice: string): Promise<void> {
|
||||
}
|
||||
|
||||
async function installCocodOrExit(): Promise<void> {
|
||||
logger.log("cocod not found. Installing globally with bun...");
|
||||
console.log("cocod not found. Installing globally with bun...");
|
||||
|
||||
const installProc = Bun.spawn(
|
||||
["bun", "install", "--global", "@routstr/cocod"],
|
||||
@@ -93,13 +93,13 @@ async function installCocodOrExit(): Promise<void> {
|
||||
|
||||
const installCode = await installProc.exited;
|
||||
if (installCode !== 0 || !(await isCocodInstalled())) {
|
||||
logger.error(
|
||||
console.error(
|
||||
"Failed to install cocod. Please run 'bun install --global @routstr/cocod' manually.",
|
||||
);
|
||||
throw new Error("cocod installation failed");
|
||||
}
|
||||
|
||||
logger.log("cocod installed successfully.");
|
||||
console.log("cocod installed successfully.");
|
||||
}
|
||||
|
||||
async function requireLocalDaemon(): Promise<void> {
|
||||
@@ -113,12 +113,12 @@ async function requireLocalDaemon(): Promise<void> {
|
||||
}
|
||||
|
||||
async function initDaemon(): Promise<void> {
|
||||
logger.log("Initializing routstrd...");
|
||||
console.log("Initializing routstrd...");
|
||||
|
||||
// Create config directory
|
||||
if (!existsSync(CONFIG_DIR)) {
|
||||
mkdirSync(CONFIG_DIR, { recursive: true });
|
||||
logger.log(`Created config directory: ${CONFIG_DIR}`);
|
||||
console.log(`Created config directory: ${CONFIG_DIR}`);
|
||||
}
|
||||
|
||||
// Create initial config
|
||||
@@ -128,7 +128,7 @@ async function initDaemon(): Promise<void> {
|
||||
cocodPath: null,
|
||||
};
|
||||
await Bun.write(CONFIG_FILE, JSON.stringify(config, null, 2));
|
||||
logger.log(`Created config file: ${CONFIG_FILE}`);
|
||||
console.log(`Created config file: ${CONFIG_FILE}`);
|
||||
}
|
||||
|
||||
const config = await loadConfig();
|
||||
@@ -190,30 +190,30 @@ async function initDaemon(): Promise<void> {
|
||||
const alreadyInitialized = combinedOutput.includes("already initialized");
|
||||
|
||||
if (initCode !== 0 && !alreadyInitialized) {
|
||||
logger.error(
|
||||
console.error(
|
||||
"Failed to initialize cocod. Please run 'cocod init' manually.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (alreadyInitialized) {
|
||||
logger.log("cocod is already initialized.");
|
||||
console.log("cocod is already initialized.");
|
||||
} else {
|
||||
logger.log("cocod initialized successfully.");
|
||||
console.log("cocod initialized successfully.");
|
||||
}
|
||||
|
||||
await startDaemon({ port: String(config.port || 8008) });
|
||||
|
||||
await setupIntegration(config);
|
||||
|
||||
logger.log("\nInitialization complete!");
|
||||
logger.log(
|
||||
console.log("\nInitialization complete!");
|
||||
console.log(
|
||||
"\n use 'routstrd receive <cashu-token>' or 'routstrd receive 2100' to top up your local wallet using Lightning!",
|
||||
);
|
||||
logger.log(
|
||||
console.log(
|
||||
"\n full wallet commands still work too, e.g. 'routstrd wallet receive cashu <token>' and 'routstrd wallet receive bolt11 2100'.",
|
||||
);
|
||||
logger.log(
|
||||
console.log(
|
||||
"\nTo ensure routstrd persists across system restarts, run: 'routstrd service install'",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import { existsSync, mkdirSync } from "fs";
|
||||
import { readFile, writeFile } from "fs/promises";
|
||||
import { dirname } from "path";
|
||||
import type { RoutstrdConfig } from "../utils/config";
|
||||
import { logger } from "../utils/logger";
|
||||
import type { IntegrationConfig, RoutstrModel } from "./registry";
|
||||
import { callDaemon, getDaemonBaseUrl } from "../utils/daemon-client";
|
||||
|
||||
@@ -13,8 +12,8 @@ export async function installClaudeCodeIntegration(
|
||||
): Promise<void> {
|
||||
const { name, configPath } = integrationConfig;
|
||||
|
||||
logger.log(`\nInstalling routstr configuration in ${configPath}...`);
|
||||
logger.log(`Using API key for ${name}`);
|
||||
console.log(`\nInstalling routstr configuration in ${configPath}...`);
|
||||
console.log(`Using API key for ${name}`);
|
||||
|
||||
const baseUrl = getDaemonBaseUrl(config);
|
||||
|
||||
@@ -28,7 +27,7 @@ export async function installClaudeCodeIntegration(
|
||||
settings = JSON.parse(content);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`Error reading ${configPath}, creating new one.`);
|
||||
console.error(`Error reading ${configPath}, creating new one.`);
|
||||
}
|
||||
|
||||
if (!settings.env) {
|
||||
@@ -49,25 +48,25 @@ export async function installClaudeCodeIntegration(
|
||||
settings.env["ANTHROPIC_DEFAULT_OPUS_MODEL"] = opus.id;
|
||||
settings.env["ANTHROPIC_DEFAULT_SONNET_MODEL"] = sonnet.id;
|
||||
settings.env["ANTHROPIC_DEFAULT_HAIKU_MODEL"] = haiku.id;
|
||||
logger.log(`Set Claude models: Opus=${opus.id}, Sonnet=${sonnet.id}, Haiku=${haiku.id}`);
|
||||
console.log(`Set Claude models: Opus=${opus.id}, Sonnet=${sonnet.id}, Haiku=${haiku.id}`);
|
||||
} else if (models.length > 0) {
|
||||
const model = models[0]!;
|
||||
logger.log(`Only ${models.length} models available, falling back to defaults.`);
|
||||
console.log(`Only ${models.length} models available, falling back to defaults.`);
|
||||
settings.env["ANTHROPIC_DEFAULT_OPUS_MODEL"] = model.id;
|
||||
settings.env["ANTHROPIC_DEFAULT_SONNET_MODEL"] = model.id;
|
||||
settings.env["ANTHROPIC_DEFAULT_HAIKU_MODEL"] = model.id;
|
||||
} else {
|
||||
logger.log("No models available from routstr daemon.");
|
||||
console.log("No models available from routstr daemon.");
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error("Failed to fetch models for Claude Code integration:", error);
|
||||
console.error("Failed to fetch models for Claude Code integration:", error);
|
||||
}
|
||||
|
||||
try {
|
||||
mkdirSync(dirname(configPath), { recursive: true });
|
||||
await writeFile(configPath, JSON.stringify(settings, null, 2));
|
||||
logger.log(`Successfully updated ${configPath} with routstr settings.`);
|
||||
console.log(`Successfully updated ${configPath} with routstr settings.`);
|
||||
} catch (error) {
|
||||
logger.error(`Failed to write to ${configPath}:`, error);
|
||||
console.error(`Failed to write to ${configPath}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
+10
-11
@@ -2,7 +2,6 @@ import { existsSync, mkdirSync } from "fs";
|
||||
import { readFile, writeFile } from "fs/promises";
|
||||
import { dirname } from "path";
|
||||
import type { RoutstrdConfig } from "../utils/config";
|
||||
import { logger } from "../utils/logger";
|
||||
import type { IntegrationConfig, RoutstrModel } from "./registry";
|
||||
import { callDaemon, getDaemonBaseUrl } from "../utils/daemon-client";
|
||||
|
||||
@@ -13,8 +12,8 @@ export async function installHermesIntegration(
|
||||
): Promise<void> {
|
||||
const { name, configPath } = integrationConfig;
|
||||
|
||||
logger.log(`\nInstalling routstr configuration in ${configPath}...`);
|
||||
logger.log(`Using API key for ${name}`);
|
||||
console.log(`\nInstalling routstr configuration in ${configPath}...`);
|
||||
console.log(`Using API key for ${name}`);
|
||||
|
||||
const baseUrl = getDaemonBaseUrl(config);
|
||||
const baseUrlV1 = `${baseUrl}/v1`;
|
||||
@@ -27,16 +26,16 @@ export async function installHermesIntegration(
|
||||
|
||||
if (models.length >= 3) {
|
||||
defaultModel = models[2]!.id;
|
||||
logger.log(`Set default model to 3rd available model: ${defaultModel}`);
|
||||
console.log(`Set default model to 3rd available model: ${defaultModel}`);
|
||||
} else if (models.length > 0) {
|
||||
defaultModel = models[0]!.id;
|
||||
logger.log(`Only ${models.length} models available, using ${defaultModel} as default.`);
|
||||
console.log(`Only ${models.length} models available, using ${defaultModel} as default.`);
|
||||
} else {
|
||||
logger.log("No models available from routstr daemon, using fallback default.");
|
||||
console.log("No models available from routstr daemon, using fallback default.");
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error("Failed to fetch models for Hermes integration:", error);
|
||||
logger.log("Using fallback default model.");
|
||||
console.error("Failed to fetch models for Hermes integration:", error);
|
||||
console.log("Using fallback default model.");
|
||||
}
|
||||
|
||||
let content = "";
|
||||
@@ -45,7 +44,7 @@ export async function installHermesIntegration(
|
||||
content = await readFile(configPath, "utf-8");
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`Error reading ${configPath}, creating new one.`);
|
||||
console.error(`Error reading ${configPath}, creating new one.`);
|
||||
}
|
||||
|
||||
// Remove existing model block
|
||||
@@ -80,8 +79,8 @@ export async function installHermesIntegration(
|
||||
try {
|
||||
mkdirSync(dirname(configPath), { recursive: true });
|
||||
await writeFile(configPath, newContent);
|
||||
logger.log(`Successfully updated ${configPath} with routstr settings.`);
|
||||
console.log(`Successfully updated ${configPath} with routstr settings.`);
|
||||
} catch (error) {
|
||||
logger.error(`Failed to write to ${configPath}:`, error);
|
||||
console.error(`Failed to write to ${configPath}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
+10
-10
@@ -67,13 +67,13 @@ function parseChoice(input: string): number {
|
||||
export async function setupIntegration(
|
||||
config: RoutstrdConfig,
|
||||
): Promise<void> {
|
||||
logger.log("\nChoose an integration to set up:");
|
||||
logger.log("1. OpenCode (default)");
|
||||
logger.log("2. OpenClaw");
|
||||
logger.log("3. Pi");
|
||||
logger.log("4. Claude Code");
|
||||
logger.log("5. Hermes");
|
||||
logger.log("6. Skip for now");
|
||||
console.log("\nChoose an integration to set up:");
|
||||
console.log("1. OpenCode (default)");
|
||||
console.log("2. OpenClaw");
|
||||
console.log("3. Pi");
|
||||
console.log("4. Claude Code");
|
||||
console.log("5. Hermes");
|
||||
console.log("6. Skip for now");
|
||||
|
||||
const answer = await ask("Select integration [1]: ");
|
||||
const choice = parseChoice(answer);
|
||||
@@ -88,7 +88,7 @@ export async function setupIntegration(
|
||||
|
||||
const key = integrationByChoice[choice];
|
||||
if (!key) {
|
||||
logger.log("Skipping integration setup.");
|
||||
console.log("Skipping integration setup.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -98,9 +98,9 @@ export async function setupIntegration(
|
||||
);
|
||||
|
||||
if (created) {
|
||||
logger.log(`Created new API key for ${integrationConfig.name}`);
|
||||
console.log(`Created new API key for ${integrationConfig.name}`);
|
||||
} else {
|
||||
logger.log(`Using existing API key for ${integrationConfig.name}`);
|
||||
console.log(`Using existing API key for ${integrationConfig.name}`);
|
||||
}
|
||||
|
||||
if (key === "opencode") {
|
||||
|
||||
@@ -2,7 +2,6 @@ import { existsSync, mkdirSync } from "fs";
|
||||
import { readFile, writeFile } from "fs/promises";
|
||||
import { dirname } from "path";
|
||||
import type { RoutstrdConfig } from "../utils/config";
|
||||
import { logger } from "../utils/logger";
|
||||
import type { IntegrationConfig, RoutstrModel } from "./registry";
|
||||
import { callDaemon, getDaemonBaseUrl } from "../utils/daemon-client";
|
||||
|
||||
@@ -56,8 +55,8 @@ export async function installOpenClawIntegration(
|
||||
): Promise<void> {
|
||||
const { name, configPath } = integrationConfig;
|
||||
|
||||
logger.log("\nInstalling routstr models in openclaw.json...");
|
||||
logger.log(`Using API key for ${name}`);
|
||||
console.log("\nInstalling routstr models in openclaw.json...");
|
||||
console.log(`Using API key for ${name}`);
|
||||
|
||||
const baseUrl = getDaemonBaseUrl(config);
|
||||
|
||||
@@ -92,7 +91,7 @@ export async function installOpenClawIntegration(
|
||||
const models = (data.output as { models: RoutstrModel[] } | undefined)?.models || [];
|
||||
|
||||
if (models.length === 0) {
|
||||
logger.log("No models found from routstr daemon.");
|
||||
console.log("No models found from routstr daemon.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -134,8 +133,8 @@ export async function installOpenClawIntegration(
|
||||
// openclawConfig.agents.defaults.models = aliasMap;
|
||||
|
||||
await writeFile(configPath, JSON.stringify(openclawConfig, null, 2));
|
||||
logger.log(`Added "${OPENCLAW_PROVIDER_ID}" provider with ${models.length} models to openclaw.json`);
|
||||
console.log(`Added "${OPENCLAW_PROVIDER_ID}" provider with ${models.length} models to openclaw.json`);
|
||||
} catch (error) {
|
||||
logger.error("Failed to install models in openclaw.json:", error);
|
||||
console.error("Failed to install models in openclaw.json:", error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import { existsSync, mkdirSync } from "fs";
|
||||
import { readFile, writeFile } from "fs/promises";
|
||||
import { dirname } from "path";
|
||||
import type { RoutstrdConfig } from "../utils/config";
|
||||
import { logger } from "../utils/logger";
|
||||
import type { IntegrationConfig, RoutstrModel } from "./registry";
|
||||
import { callDaemon, getDaemonBaseUrl } from "../utils/daemon-client";
|
||||
|
||||
@@ -15,8 +14,8 @@ export async function installOpencodeIntegration(
|
||||
): Promise<void> {
|
||||
const { name, configPath } = integrationConfig;
|
||||
|
||||
logger.log("\nInstalling routstr models in opencode.json...");
|
||||
logger.log(`Using API key for ${name}`);
|
||||
console.log("\nInstalling routstr models in opencode.json...");
|
||||
console.log(`Using API key for ${name}`);
|
||||
|
||||
const baseUrl = getDaemonBaseUrl(config);
|
||||
|
||||
@@ -56,7 +55,7 @@ export async function installOpencodeIntegration(
|
||||
const models = (data.output as { models: RoutstrModel[] } | undefined)?.models || [];
|
||||
|
||||
if (models.length === 0) {
|
||||
logger.log("No models found from routstr daemon.");
|
||||
console.log("No models found from routstr daemon.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -78,8 +77,8 @@ export async function installOpencodeIntegration(
|
||||
opencodeConfig.small_model = OPENCODE_SMALL_MODEL;
|
||||
|
||||
await writeFile(configPath, JSON.stringify(opencodeConfig, null, 2));
|
||||
logger.log(`Added "routstr" provider with ${models.length} models to opencode.json`);
|
||||
console.log(`Added "routstr" provider with ${models.length} models to opencode.json`);
|
||||
} catch (error) {
|
||||
logger.error("Failed to install models in opencode.json:", error);
|
||||
console.error("Failed to install models in opencode.json:", error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import { existsSync, mkdirSync } from "fs";
|
||||
import { readFile, writeFile } from "fs/promises";
|
||||
import { dirname } from "path";
|
||||
import type { RoutstrdConfig } from "../utils/config";
|
||||
import { logger } from "../utils/logger";
|
||||
import type { IntegrationConfig, RoutstrModel } from "./registry";
|
||||
import { callDaemon, getDaemonBaseUrl } from "../utils/daemon-client";
|
||||
|
||||
@@ -28,8 +27,8 @@ export async function installPiIntegration(
|
||||
): Promise<void> {
|
||||
const { name, configPath } = integrationConfig;
|
||||
|
||||
logger.log("\nInstalling routstr models in pi models.json...");
|
||||
logger.log(`Using API key for ${name}`);
|
||||
console.log("\nInstalling routstr models in pi models.json...");
|
||||
console.log(`Using API key for ${name}`);
|
||||
|
||||
const baseUrl = `${getDaemonBaseUrl(config)}/v1`;
|
||||
|
||||
@@ -56,7 +55,7 @@ export async function installPiIntegration(
|
||||
const models = (data.output as { models: RoutstrModel[] } | undefined)?.models || [];
|
||||
|
||||
if (models.length === 0) {
|
||||
logger.log("No models found from routstr daemon.");
|
||||
console.log("No models found from routstr daemon.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -72,8 +71,8 @@ export async function installPiIntegration(
|
||||
};
|
||||
|
||||
await writeFile(configPath, JSON.stringify(piConfig, null, 2));
|
||||
logger.log(`Added "routstr" provider with ${models.length} models to pi models.json`);
|
||||
console.log(`Added "routstr" provider with ${models.length} models to pi models.json`);
|
||||
} catch (error) {
|
||||
logger.error("Failed to install models in pi models.json:", error);
|
||||
console.error("Failed to install models in pi models.json:", error);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user