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_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",
|
"name": "@companion-ai/feynman",
|
||||||
"version": "0.2.9",
|
"version": "0.2.10",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@companion-ai/feynman",
|
"name": "@companion-ai/feynman",
|
||||||
"version": "0.2.9",
|
"version": "0.2.10",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@companion-ai/alpha-hub": "^0.1.2",
|
"@companion-ai/alpha-hub": "^0.1.2",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@companion-ai/feynman",
|
"name": "@companion-ai/feynman",
|
||||||
"version": "0.2.9",
|
"version": "0.2.10",
|
||||||
"description": "Research-first CLI agent built on Pi and alphaXiv",
|
"description": "Research-first CLI agent built on Pi and alphaXiv",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"engines": {
|
"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 { CORE_PACKAGE_SOURCES, getOptionalPackagePresetSources, listOptionalPackagePresets } from "./pi/package-presets.js";
|
||||||
import { normalizeFeynmanSettings, normalizeThinkingLevel, parseModelSpec } from "./pi/settings.js";
|
import { normalizeFeynmanSettings, normalizeThinkingLevel, parseModelSpec } from "./pi/settings.js";
|
||||||
import {
|
import {
|
||||||
|
getCurrentModelSpec,
|
||||||
loginModelProvider,
|
loginModelProvider,
|
||||||
logoutModelProvider,
|
logoutModelProvider,
|
||||||
printModelList,
|
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({
|
await launchPiChat({
|
||||||
appRoot,
|
appRoot,
|
||||||
workingDir,
|
workingDir,
|
||||||
|
|||||||
@@ -191,33 +191,23 @@ export function setDefaultModelSpec(settingsPath: string, authPath: string, spec
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function runModelSetup(settingsPath: string, authPath: string): Promise<void> {
|
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) {
|
if (status.availableModels.length === 0) {
|
||||||
printWarning("No Pi models are currently authenticated for Feynman.");
|
await loginModelProvider(authPath, undefined, settingsPath);
|
||||||
for (const line of status.guidance) {
|
status = collectModelStatus(settingsPath, authPath);
|
||||||
printInfo(line);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const choices = status.availableModels.map((spec) => {
|
const recommended = status.recommended ?? status.availableModels[0];
|
||||||
const markers = [
|
if (recommended) {
|
||||||
spec === status.recommended ? "recommended" : undefined,
|
setDefaultModelSpec(settingsPath, authPath, recommended);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 { getCurrentModelSpec, runModelSetup } from "../model/commands.js";
|
||||||
import { buildModelStatusSnapshotFromRecords, getAvailableModelRecords, getSupportedModelRecords } from "../model/catalog.js";
|
import { buildModelStatusSnapshotFromRecords, getAvailableModelRecords, getSupportedModelRecords } from "../model/catalog.js";
|
||||||
import { PANDOC_FALLBACK_PATHS, resolveExecutable } from "../system/executables.js";
|
import { PANDOC_FALLBACK_PATHS, resolveExecutable } from "../system/executables.js";
|
||||||
import { promptText } from "./prompts.js";
|
|
||||||
import { setupPreviewDependencies } from "./preview.js";
|
import { setupPreviewDependencies } from "./preview.js";
|
||||||
import { runDoctor } from "./doctor.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 = {
|
type SetupOptions = {
|
||||||
settingsPath: string;
|
settingsPath: string;
|
||||||
@@ -22,129 +21,16 @@ type SetupOptions = {
|
|||||||
defaultThinkingLevel?: ThinkingLevel;
|
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 {
|
function isInteractiveTerminal(): boolean {
|
||||||
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
function printNonInteractiveSetupGuidance(): void {
|
function printNonInteractiveSetupGuidance(): void {
|
||||||
printPanel("Feynman Setup", [
|
printInfo("Non-interactive terminal. Use explicit commands:");
|
||||||
"Non-interactive terminal detected.",
|
|
||||||
]);
|
|
||||||
printInfo("Use the explicit commands instead of the interactive setup wizard:");
|
|
||||||
printInfo(" feynman status");
|
|
||||||
printInfo(" feynman model login <provider>");
|
printInfo(" feynman model login <provider>");
|
||||||
printInfo(" feynman model set <provider/model>");
|
printInfo(" feynman model set <provider/model>");
|
||||||
printInfo(" feynman search status");
|
|
||||||
printInfo(` edit ${getPiWebSearchConfigPath()} # optional advanced web config`);
|
|
||||||
printInfo(" feynman alpha login");
|
printInfo(" feynman alpha login");
|
||||||
printInfo(" feynman doctor");
|
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> {
|
export async function runSetup(options: SetupOptions): Promise<void> {
|
||||||
@@ -153,5 +39,31 @@ export async function runSetup(options: SetupOptions): Promise<void> {
|
|||||||
return;
|
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