From 82790506d3b9dfb0607403fb4de812fc67674bbb Mon Sep 17 00:00:00 2001 From: Advait Paliwal Date: Mon, 23 Mar 2026 23:43:32 -0700 Subject: [PATCH] Fix OAuth logo: override .logo size constraint, use @import for VT323 font Co-Authored-By: Claude Opus 4.6 (1M context) --- logo.mjs | 2 +- package-lock.json | 4 +- package.json | 2 +- src/cli.ts | 17 +++++ src/model/commands.ts | 34 ++++------ src/setup/setup.ts | 146 +++++++++--------------------------------- 6 files changed, 62 insertions(+), 143 deletions(-) diff --git a/logo.mjs b/logo.mjs index 268d2ea..34f0eaf 100644 --- a/logo.mjs +++ b/logo.mjs @@ -12,4 +12,4 @@ export const FEYNMAN_ASCII_LOGO = [ export const FEYNMAN_ASCII_LOGO_TEXT = FEYNMAN_ASCII_LOGO.join("\n"); -export const FEYNMAN_LOGO_HTML = `feynman`; +export const FEYNMAN_LOGO_HTML = `feynman`; diff --git a/package-lock.json b/package-lock.json index 06f6b5d..23d4e26 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@companion-ai/feynman", - "version": "0.2.9", + "version": "0.2.10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@companion-ai/feynman", - "version": "0.2.9", + "version": "0.2.10", "hasInstallScript": true, "dependencies": { "@companion-ai/alpha-hub": "^0.1.2", diff --git a/package.json b/package.json index b070820..85a71dc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@companion-ai/feynman", - "version": "0.2.9", + "version": "0.2.10", "description": "Research-first CLI agent built on Pi and alphaXiv", "type": "module", "engines": { diff --git a/src/cli.ts b/src/cli.ts index 443b516..6e9b3fb 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -19,6 +19,7 @@ import { launchPiChat } from "./pi/launch.js"; import { CORE_PACKAGE_SOURCES, getOptionalPackagePresetSources, listOptionalPackagePresets } from "./pi/package-presets.js"; import { normalizeFeynmanSettings, normalizeThinkingLevel, parseModelSpec } from "./pi/settings.js"; import { + getCurrentModelSpec, loginModelProvider, logoutModelProvider, printModelList, @@ -424,6 +425,22 @@ export async function main(): Promise { } } + if (!explicitModelSpec && !getCurrentModelSpec(feynmanSettingsPath) && process.stdin.isTTY && process.stdout.isTTY) { + await runSetup({ + settingsPath: feynmanSettingsPath, + bundledSettingsPath, + authPath: feynmanAuthPath, + workingDir, + sessionDir, + appRoot, + defaultThinkingLevel: thinkingLevel, + }); + if (!getCurrentModelSpec(feynmanSettingsPath)) { + return; + } + normalizeFeynmanSettings(feynmanSettingsPath, bundledSettingsPath, thinkingLevel, feynmanAuthPath); + } + await launchPiChat({ appRoot, workingDir, diff --git a/src/model/commands.ts b/src/model/commands.ts index 6d8df32..b43b132 100644 --- a/src/model/commands.ts +++ b/src/model/commands.ts @@ -191,33 +191,23 @@ export function setDefaultModelSpec(settingsPath: string, authPath: string, spec } export async function runModelSetup(settingsPath: string, authPath: string): Promise { - const status = collectModelStatus(settingsPath, authPath); + let status = collectModelStatus(settingsPath, authPath); if (status.availableModels.length === 0) { - printWarning("No Pi models are currently authenticated for Feynman."); - for (const line of status.guidance) { - printInfo(line); + await loginModelProvider(authPath, undefined, settingsPath); + status = collectModelStatus(settingsPath, authPath); + if (status.availableModels.length === 0) { + return; } - printInfo("Tip: run `feynman model login ` if your provider supports Pi OAuth login."); + } + + if (status.currentValid) { + printInfo(`Model: ${status.current}`); return; } - const choices = status.availableModels.map((spec) => { - const markers = [ - spec === status.recommended ? "recommended" : undefined, - spec === status.current ? "current" : undefined, - ].filter(Boolean); - return `${spec}${markers.length > 0 ? ` (${markers.join(", ")})` : ""}`; - }); - choices.push(`Keep current (${status.current ?? "unset"})`); - - const defaultIndex = status.current ? Math.max(0, status.availableModels.indexOf(status.current)) : 0; - const selection = await promptChoice("Select your default research model:", choices, defaultIndex >= 0 ? defaultIndex : 0); - - if (selection >= status.availableModels.length) { - printInfo("Skipped (keeping current model)"); - return; + const recommended = status.recommended ?? status.availableModels[0]; + if (recommended) { + setDefaultModelSpec(settingsPath, authPath, recommended); } - - setDefaultModelSpec(settingsPath, authPath, status.availableModels[selection]!); } diff --git a/src/setup/setup.ts b/src/setup/setup.ts index e8f3569..aec4d11 100644 --- a/src/setup/setup.ts +++ b/src/setup/setup.ts @@ -7,10 +7,9 @@ import type { ThinkingLevel } from "../pi/settings.js"; import { getCurrentModelSpec, runModelSetup } from "../model/commands.js"; import { buildModelStatusSnapshotFromRecords, getAvailableModelRecords, getSupportedModelRecords } from "../model/catalog.js"; import { PANDOC_FALLBACK_PATHS, resolveExecutable } from "../system/executables.js"; -import { promptText } from "./prompts.js"; import { setupPreviewDependencies } from "./preview.js"; import { runDoctor } from "./doctor.js"; -import { printInfo, printPanel, printSection, printSuccess } from "../ui/terminal.js"; +import { printInfo, printSection, printSuccess } from "../ui/terminal.js"; type SetupOptions = { settingsPath: string; @@ -22,129 +21,16 @@ type SetupOptions = { defaultThinkingLevel?: ThinkingLevel; }; -async function explainWebAccess(): Promise { - const status = getPiWebAccessStatus(); - printSection("Web Access"); - printInfo("Feynman uses the bundled `pi-web-access` package directly."); - printInfo("Default v1 path: sign into gemini.google.com in a supported Chromium browser."); - printInfo(`Current search route: ${status.routeLabel}`); - printInfo(`Pi config path: ${status.configPath}`); - printInfo("Advanced users can edit the Pi config directly if they want API keys or a different route."); -} - -function isPreviewConfigured() { - return Boolean(resolveExecutable("pandoc", PANDOC_FALLBACK_PATHS)); -} - function isInteractiveTerminal(): boolean { return Boolean(process.stdin.isTTY && process.stdout.isTTY); } function printNonInteractiveSetupGuidance(): void { - printPanel("Feynman Setup", [ - "Non-interactive terminal detected.", - ]); - printInfo("Use the explicit commands instead of the interactive setup wizard:"); - printInfo(" feynman status"); + printInfo("Non-interactive terminal. Use explicit commands:"); printInfo(" feynman model login "); printInfo(" feynman model set "); - printInfo(" feynman search status"); - printInfo(` edit ${getPiWebSearchConfigPath()} # optional advanced web config`); printInfo(" feynman alpha login"); printInfo(" feynman doctor"); - printInfo(" feynman # Pi's /login flow still works inside chat if you prefer it"); -} - -async function runPreviewSetup(): Promise { - const result = setupPreviewDependencies(); - printSuccess(result.message); -} - -function printConfigurationLocation(appRoot: string): void { - printSection("Configuration Location"); - printInfo(`Data folder: ${getFeynmanHome()}`); - printInfo(`Sessions: ${getDefaultSessionDir()}`); - printInfo(`Install dir: ${appRoot}`); -} - -function printSetupSummary(settingsPath: string, authPath: string): void { - const modelStatus = buildModelStatusSnapshotFromRecords( - getSupportedModelRecords(authPath), - getAvailableModelRecords(authPath), - getCurrentModelSpec(settingsPath), - ); - printSection("Setup Summary"); - printInfo(`Model: ${getCurrentModelSpec(settingsPath) ?? "not set"}`); - printInfo(`Model valid: ${modelStatus.currentValid ? "yes" : "no"}`); - printInfo(`Recommended model: ${modelStatus.recommended ?? "not available"}`); - printInfo(`alphaXiv: ${isAlphaLoggedIn() ? "configured" : "missing"}`); - printInfo(`Web access: pi-web-access (${getPiWebAccessStatus().routeLabel})`); - printInfo(`Preview: ${isPreviewConfigured() ? "configured" : "not configured"}`); - for (const line of modelStatus.guidance) { - printInfo(line); - } -} - -async function runFullSetup(options: SetupOptions): Promise { - printConfigurationLocation(options.appRoot); - await runModelSetup(options.settingsPath, options.authPath); - if (!isAlphaLoggedIn()) { - await loginAlpha(); - printSuccess("alphaXiv login complete"); - } else { - printInfo("alphaXiv login already configured"); - } - await explainWebAccess(); - await runPreviewSetup(); - normalizeFeynmanSettings( - options.settingsPath, - options.bundledSettingsPath, - options.defaultThinkingLevel ?? "medium", - options.authPath, - ); - runDoctor({ - settingsPath: options.settingsPath, - authPath: options.authPath, - sessionDir: options.sessionDir, - workingDir: options.workingDir, - appRoot: options.appRoot, - }); - printSetupSummary(options.settingsPath, options.authPath); -} - -function hasExistingSetup(settingsPath: string, authPath: string): boolean { - const modelStatus = buildModelStatusSnapshotFromRecords( - getSupportedModelRecords(authPath), - getAvailableModelRecords(authPath), - getCurrentModelSpec(settingsPath), - ); - return Boolean( - modelStatus.current || - modelStatus.availableModels.length > 0 || - isAlphaLoggedIn() || - isPreviewConfigured(), - ); -} - -async function runDefaultInteractiveSetup(options: SetupOptions): Promise { - const existing = hasExistingSetup(options.settingsPath, options.authPath); - printPanel("Feynman Setup Wizard", [ - "Guided setup for the research-first Pi agent.", - "Press Ctrl+C at any time to exit.", - ]); - - if (existing) { - printSection("Full Setup"); - printInfo("Existing configuration detected. Rerunning the full guided setup."); - } else { - printInfo("We'll walk you through:"); - printInfo(" 1. Model Selection"); - printInfo(" 2. alphaXiv Login"); - printInfo(" 3. Preview Dependencies"); - } - printInfo("Press Enter to begin, or Ctrl+C to exit."); - await promptText("Press Enter to start"); - await runFullSetup(options); } export async function runSetup(options: SetupOptions): Promise { @@ -153,5 +39,31 @@ export async function runSetup(options: SetupOptions): Promise { return; } - await runDefaultInteractiveSetup(options); + await runModelSetup(options.settingsPath, options.authPath); + + if (!isAlphaLoggedIn()) { + await loginAlpha(); + printSuccess("alphaXiv login complete"); + } + + const result = setupPreviewDependencies(); + printSuccess(result.message); + + normalizeFeynmanSettings( + options.settingsPath, + options.bundledSettingsPath, + options.defaultThinkingLevel ?? "medium", + options.authPath, + ); + + const modelStatus = buildModelStatusSnapshotFromRecords( + getSupportedModelRecords(options.authPath), + getAvailableModelRecords(options.authPath), + getCurrentModelSpec(options.settingsPath), + ); + printSection("Ready"); + printInfo(`Model: ${getCurrentModelSpec(options.settingsPath) ?? "not set"}`); + printInfo(`alphaXiv: ${isAlphaLoggedIn() ? "configured" : "not configured"}`); + printInfo(`Preview: ${resolveExecutable("pandoc", PANDOC_FALLBACK_PATHS) ? "configured" : "not configured"}`); + printInfo(`Web: ${getPiWebAccessStatus().routeLabel}`); }