Fix OAuth logo: override .logo size constraint, use @import for VT323 font
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2
logo.mjs
2
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 = `<link href="https://fonts.googleapis.com/css2?family=VT323&display=swap" rel="stylesheet"><span style="font-family:'VT323',monospace;font-size:64px;letter-spacing:-0.05em;color:#10b981">feynman</span>`;
|
||||
export const FEYNMAN_LOGO_HTML = `<style>@import url('https://fonts.googleapis.com/css2?family=VT323&display=swap');.logo{width:auto!important;height:auto!important}</style><span style="font-family:'VT323',monospace;font-size:64px;letter-spacing:-0.05em;color:#10b981">feynman</span>`;
|
||||
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -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": {
|
||||
|
||||
17
src/cli.ts
17
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<void> {
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
|
||||
@@ -191,33 +191,23 @@ export function setDefaultModelSpec(settingsPath: string, authPath: string, spec
|
||||
}
|
||||
|
||||
export async function runModelSetup(settingsPath: string, authPath: string): Promise<void> {
|
||||
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 <provider>` 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]!);
|
||||
}
|
||||
|
||||
@@ -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<void> {
|
||||
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 <provider>");
|
||||
printInfo(" feynman model set <provider/model>");
|
||||
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<void> {
|
||||
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<void> {
|
||||
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<void> {
|
||||
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<void> {
|
||||
@@ -153,5 +39,31 @@ export async function runSetup(options: SetupOptions): Promise<void> {
|
||||
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}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user