Files
routstrd/src/integrations/claudecode.ts
T
Jeroen UbbinkandClaude Sonnet 4.6 739034b043 fix(onboard): show integration menu and progress in terminal
The logger utility in this project is a file-only logger — every call to
logger.log() / logger.error() writes to ~/.routstrd/logs/YYYY-MM-DD.log
and produces no terminal output whatsoever. This is intentional and correct
for the background daemon (daemon/, start-daemon.ts), which has no attached
terminal.

However, the onboarding and integration code was mistakenly using logger.log
instead of console.log for all of its user-facing output:

- setupIntegration() printed the 1-6 integration menu with logger.log, so
  the user only ever saw the bare prompt 'Select integration [1]: ' with no
  options above it. The selection appeared to be broken.

- Every install*Integration function (opencode, openclaw, claudecode, hermes,
  pi) reported all progress and results with logger.log, so after picking an
  integration nothing appeared to happen.

- initDaemon() used logger.log for 'Initialization complete!' and the
  follow-up wallet instructions, so those were also silently dropped.

- installCocodOrExit() used logger.log for the 'cocod not found, installing'
  message and the success/failure result.

Fix: replace logger.log/logger.error with console.log/console.error in all
CLI-facing code paths (cli.ts, integrations/index.ts, and all five
integration installers). Remove the now-unused logger import from the five
integration files. The logger import in integrations/index.ts is kept because
refreshModelsAndIntegrations() is called by the daemon's internal scheduler
and correctly logs to file there.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 09:02:36 +02:00

73 lines
2.5 KiB
TypeScript

import { existsSync, mkdirSync } from "fs";
import { readFile, writeFile } from "fs/promises";
import { dirname } from "path";
import type { RoutstrdConfig } from "../utils/config";
import type { IntegrationConfig, RoutstrModel } from "./registry";
import { callDaemon, getDaemonBaseUrl } from "../utils/daemon-client";
export async function installClaudeCodeIntegration(
config: RoutstrdConfig,
apiKey: string,
integrationConfig: IntegrationConfig,
): Promise<void> {
const { name, configPath } = integrationConfig;
console.log(`\nInstalling routstr configuration in ${configPath}...`);
console.log(`Using API key for ${name}`);
const baseUrl = getDaemonBaseUrl(config);
let settings: {
env?: Record<string, string>;
} = {};
try {
if (existsSync(configPath)) {
const content = await readFile(configPath, "utf-8");
settings = JSON.parse(content);
}
} catch (error) {
console.error(`Error reading ${configPath}, creating new one.`);
}
if (!settings.env) {
settings.env = {};
}
settings.env["ANTHROPIC_AUTH_TOKEN"] = apiKey;
settings.env["ANTHROPIC_BASE_URL"] = baseUrl;
try {
const data = await callDaemon("/models");
const models = (data.output as { models: RoutstrModel[] } | undefined)?.models || [];
if (models.length >= 3) {
const opus = models[0]!;
const sonnet = models[1]!;
const haiku = models[2]!;
settings.env["ANTHROPIC_DEFAULT_OPUS_MODEL"] = opus.id;
settings.env["ANTHROPIC_DEFAULT_SONNET_MODEL"] = sonnet.id;
settings.env["ANTHROPIC_DEFAULT_HAIKU_MODEL"] = 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]!;
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 {
console.log("No models available from routstr daemon.");
}
} catch (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));
console.log(`Successfully updated ${configPath} with routstr settings.`);
} catch (error) {
console.error(`Failed to write to ${configPath}:`, error);
}
}