From a692ca773c4f1baaace3a31c3c3802927ff65ff6 Mon Sep 17 00:00:00 2001 From: mforce <> Date: Sun, 3 May 2026 20:31:24 -0700 Subject: [PATCH 1/3] fix: empty token in config overrides provider default + hardcoded error - setup.ts: don't save token when empty so provider default kicks in - cli.ts: treat empty-string config values as undefined in ?? chain - cli.ts: error messages show actual provider name + suggest setup - setup.ts: show provider defaults in prompts when saved value differs --- src/cli.ts | 8 ++++---- src/setup.ts | 21 +++++++++++++++------ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index 4972122..7999684 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -163,18 +163,18 @@ async function main(): Promise { } const baseUrl = - values["base-url"] ?? process.env.CLAUDELY_BASE_URL ?? config.baseUrl ?? provider.defaultBaseUrl(); - const token = values.token ?? process.env.CLAUDELY_TOKEN ?? config.token ?? provider.defaultToken; + values["base-url"] ?? process.env.CLAUDELY_BASE_URL ?? (config.baseUrl || undefined) ?? provider.defaultBaseUrl(); + const token = values.token ?? process.env.CLAUDELY_TOKEN ?? (config.token || undefined) ?? provider.defaultToken; if (!baseUrl) { console.error( - "claudely: provider 'custom' requires --base-url (or $CLAUDELY_BASE_URL)", + `claudely: provider '${providerName}' requires --base-url (or $CLAUDELY_BASE_URL, or run \`claudely setup\`)`, ); return 2; } if (!token) { console.error( - "claudely: provider 'custom' requires --token (or $CLAUDELY_TOKEN)", + `claudely: provider '${providerName}' requires --token (or $CLAUDELY_TOKEN, or run \`claudely setup\`)`, ); return 2; } diff --git a/src/setup.ts b/src/setup.ts index b4fa060..a4ce401 100644 --- a/src/setup.ts +++ b/src/setup.ts @@ -29,14 +29,22 @@ export async function runSetup(): Promise { const provider = PROVIDERS[providerName]; + const providerDefault = provider.defaultBaseUrl(); const baseUrl = await input({ - message: "Base URL", - default: existing.baseUrl ?? provider.defaultBaseUrl(), + message: existing.baseUrl && existing.baseUrl !== providerDefault + ? `Base URL (provider default: ${providerDefault})` + : "Base URL", + default: existing.baseUrl || providerDefault, }); + const tokenDefault = provider.defaultToken; const token = await input({ - message: "Auth token", - default: existing.token ?? provider.defaultToken, + message: tokenDefault + ? existing.token && existing.token !== tokenDefault + ? `Auth token (provider default: ${tokenDefault})` + : "Auth token" + : "Auth token (required)", + default: existing.token || tokenDefault, }); let models: ModelEntry[] = []; @@ -73,13 +81,14 @@ export async function runSetup(): Promise { if (manual) model = manual; } - const config: ClaudelyConfig = { provider: providerName, baseUrl, token }; + const config: ClaudelyConfig = { provider: providerName, baseUrl }; + if (token) config.token = token; if (model) config.model = model; console.log("\nConfig to save:"); console.log(` provider: ${config.provider}`); console.log(` baseUrl: ${config.baseUrl}`); - console.log(` token: ${config.token}`); + console.log(` token: ${config.token ?? "(provider default)"}`); if (config.model) console.log(` model: ${config.model}`); console.log(); From f7f8c4229f2619c2aa111fa9172a43b754720653 Mon Sep 17 00:00:00 2001 From: mforce <> Date: Sun, 3 May 2026 20:40:33 -0700 Subject: [PATCH 2/3] feat: setup wizard offers current/default/custom choices for URL and token When a saved config exists with a value differing from the provider default, the wizard now shows a select menu with three options: - Current saved value - Provider default - Custom (opens text input) On first run (no saved config), shows a simple text input with the provider default pre-filled. --- src/setup.ts | 49 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/src/setup.ts b/src/setup.ts index a4ce401..02947c8 100644 --- a/src/setup.ts +++ b/src/setup.ts @@ -30,22 +30,43 @@ export async function runSetup(): Promise { const provider = PROVIDERS[providerName]; const providerDefault = provider.defaultBaseUrl(); - const baseUrl = await input({ - message: existing.baseUrl && existing.baseUrl !== providerDefault - ? `Base URL (provider default: ${providerDefault})` - : "Base URL", - default: existing.baseUrl || providerDefault, - }); + let baseUrl: string; + if (existing.baseUrl && existing.baseUrl !== providerDefault) { + const CUSTOM = "__custom__"; + const picked = await select({ + message: "Base URL", + choices: [ + { name: `${existing.baseUrl} (current)`, value: existing.baseUrl }, + { name: `${providerDefault} (${providerName} default)`, value: providerDefault }, + { name: "Custom URL", value: CUSTOM }, + ], + }); + baseUrl = picked === CUSTOM + ? await input({ message: "Base URL", default: existing.baseUrl }) + : picked; + } else { + baseUrl = await input({ message: "Base URL", default: providerDefault }); + } const tokenDefault = provider.defaultToken; - const token = await input({ - message: tokenDefault - ? existing.token && existing.token !== tokenDefault - ? `Auth token (provider default: ${tokenDefault})` - : "Auth token" - : "Auth token (required)", - default: existing.token || tokenDefault, - }); + let token: string; + if (existing.token && existing.token !== tokenDefault) { + const CUSTOM = "__custom__"; + const choices = [ + { name: `${existing.token} (current)`, value: existing.token }, + ]; + if (tokenDefault) choices.push({ name: `${tokenDefault} (${providerName} default)`, value: tokenDefault }); + choices.push({ name: "Custom token", value: CUSTOM }); + const picked = await select({ message: "Auth token", choices }); + token = picked === CUSTOM + ? await input({ message: "Auth token", default: existing.token }) + : picked; + } else { + token = await input({ + message: tokenDefault ? "Auth token" : "Auth token (required)", + default: tokenDefault, + }); + } let models: ModelEntry[] = []; try { From 954e778fc0bbfbaab645c73f716983ef5b8975eb Mon Sep 17 00:00:00 2001 From: mforce <> Date: Sun, 3 May 2026 20:42:16 -0700 Subject: [PATCH 3/3] fix: simplify auth token prompt to plain input --- src/setup.ts | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/src/setup.ts b/src/setup.ts index 02947c8..8c78ef5 100644 --- a/src/setup.ts +++ b/src/setup.ts @@ -49,24 +49,12 @@ export async function runSetup(): Promise { } const tokenDefault = provider.defaultToken; - let token: string; - if (existing.token && existing.token !== tokenDefault) { - const CUSTOM = "__custom__"; - const choices = [ - { name: `${existing.token} (current)`, value: existing.token }, - ]; - if (tokenDefault) choices.push({ name: `${tokenDefault} (${providerName} default)`, value: tokenDefault }); - choices.push({ name: "Custom token", value: CUSTOM }); - const picked = await select({ message: "Auth token", choices }); - token = picked === CUSTOM - ? await input({ message: "Auth token", default: existing.token }) - : picked; - } else { - token = await input({ - message: tokenDefault ? "Auth token" : "Auth token (required)", - default: tokenDefault, - }); - } + const token = await input({ + message: existing.token + ? "Auth token (Enter to keep current, blank to clear)" + : tokenDefault ? "Auth token" : "Auth token (required)", + default: existing.token || tokenDefault, + }); let models: ModelEntry[] = []; try {