diff --git a/extensions/research-tools/header.ts b/extensions/research-tools/header.ts index d0baf31..4871c9c 100644 --- a/extensions/research-tools/header.ts +++ b/extensions/research-tools/header.ts @@ -230,8 +230,10 @@ export function installFeynmanHeader( push(""); if (cardW >= 70) { + const maxLogoW = Math.max(...FEYNMAN_AGENT_LOGO.map((l) => l.length)); + const logoOffset = " ".repeat(Math.max(0, Math.floor((cardW - maxLogoW) / 2))); for (const logoLine of FEYNMAN_AGENT_LOGO) { - push(theme.fg("accent", theme.bold(centerText(truncateVisible(logoLine, cardW), cardW)))); + push(theme.fg("accent", theme.bold(`${logoOffset}${truncateVisible(logoLine, cardW)}`))); } push(""); } diff --git a/logo.d.mts b/logo.d.mts index 1552567..49ba517 100644 --- a/logo.d.mts +++ b/logo.d.mts @@ -1,3 +1,3 @@ export declare const FEYNMAN_ASCII_LOGO: string[]; export declare const FEYNMAN_ASCII_LOGO_TEXT: string; -export declare const FEYNMAN_ASCII_LOGO_HTML: string; +export declare const FEYNMAN_LOGO_HTML: string; diff --git a/logo.mjs b/logo.mjs index dd55f47..268d2ea 100644 --- a/logo.mjs +++ b/logo.mjs @@ -1,12 +1,15 @@ 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/scripts/patch-embedded-pi.mjs b/scripts/patch-embedded-pi.mjs index cc0c657..b459f13 100644 --- a/scripts/patch-embedded-pi.mjs +++ b/scripts/patch-embedded-pi.mjs @@ -2,7 +2,7 @@ import { spawnSync } from "node:child_process"; import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; import { dirname, resolve } from "node:path"; import { fileURLToPath } from "node:url"; -import { FEYNMAN_ASCII_LOGO_HTML } from "../logo.mjs"; +import { FEYNMAN_LOGO_HTML } from "../logo.mjs"; const here = dirname(fileURLToPath(import.meta.url)); const appRoot = resolve(here, ".."); @@ -365,7 +365,7 @@ if (oauthPagePath && existsSync(oauthPagePath)) { let source = readFileSync(oauthPagePath, "utf8"); const piLogo = 'const LOGO_SVG = ``;'; if (source.includes(piLogo)) { - const feynmanLogo = `const LOGO_SVG = \`${FEYNMAN_ASCII_LOGO_HTML}\`;`; + const feynmanLogo = `const LOGO_SVG = \`${FEYNMAN_LOGO_HTML}\`;`; source = source.replace(piLogo, feynmanLogo); writeFileSync(oauthPagePath, source, "utf8"); } @@ -377,17 +377,17 @@ const alphaHubAuthPath = findPackageRoot("@companion-ai/alpha-hub") if (alphaHubAuthPath && existsSync(alphaHubAuthPath)) { let source = readFileSync(alphaHubAuthPath, "utf8"); - const callbackStyle = `style="font-family:system-ui,sans-serif;display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:80vh;background:#050a08;color:#f0f5f2"`; - const logoHtml = FEYNMAN_ASCII_LOGO_HTML.replace('color:#10b981', 'color:#34d399'); - const successPage = `
${logoHtml}You can close this tab.
`; - const errorPage = `${logoHtml}You can close this tab.
`; - const oldSuccess = `'You can close this tab.
'`; - const oldError = `'You can close this tab.
'`; + const oldSuccess = "'You can close this tab.
'"; + const oldError = "'You can close this tab.
'"; + const bodyAttr = `style="font-family:system-ui,sans-serif;text-align:center;padding-top:20vh;background:#050a08;color:#f0f5f2"`; + const logo = `You can close this tab.
'`; + const newError = `'${logo}You can close this tab.
'`; if (source.includes(oldSuccess)) { - source = source.replace(oldSuccess, `'${successPage}'`); + source = source.replace(oldSuccess, newSuccess); } if (source.includes(oldError)) { - source = source.replace(oldError, `'${errorPage}'`); + source = source.replace(oldError, newError); } writeFileSync(alphaHubAuthPath, source, "utf8"); } diff --git a/src/cli.ts b/src/cli.ts index bd16cc5..443b516 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -28,7 +28,7 @@ import { printSearchStatus } from "./search/commands.js"; import { runDoctor, runStatus } from "./setup/doctor.js"; import { setupPreviewDependencies } from "./setup/preview.js"; import { runSetup } from "./setup/setup.js"; -import { printInfo, printPanel, printSection } from "./ui/terminal.js"; +import { printAsciiHeader, printInfo, printPanel, printSection } from "./ui/terminal.js"; import { cliCommandSections, formatCliWorkflowUsage, @@ -50,7 +50,7 @@ function printHelp(appRoot: string): void { (command) => command.section === "Research Workflows" && command.topLevelCli, ); - printPanel("Feynman", [ + printAsciiHeader([ "Research-first agent shell built on Pi.", "Use `feynman setup` first if this is a new machine.", ]); @@ -123,7 +123,7 @@ async function handleModelCommand(subcommand: string | undefined, args: string[] } if (subcommand === "login") { - await loginModelProvider(feynmanAuthPath, args[0]); + await loginModelProvider(feynmanAuthPath, args[0], feynmanSettingsPath); return; } diff --git a/src/model/commands.ts b/src/model/commands.ts index 40a602f..6d8df32 100644 --- a/src/model/commands.ts +++ b/src/model/commands.ts @@ -6,6 +6,7 @@ import { promptChoice, promptText } from "../setup/prompts.js"; import { printInfo, printSection, printSuccess, printWarning } from "../ui/terminal.js"; import { buildModelStatusSnapshotFromRecords, + chooseRecommendedModel, getAvailableModelRecords, getSupportedModelRecords, type ModelStatusSnapshot, @@ -109,7 +110,7 @@ export function printModelList(settingsPath: string, authPath: string): void { } } -export async function loginModelProvider(authPath: string, providerId?: string): Promise