Remove legacy chains, skills, and config modules. Add citation agent, SYSTEM.md, modular research-tools extension, and web-access layer. Add ralph-wiggum to Pi package stack for long-running loops. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
167 lines
6.6 KiB
TypeScript
167 lines
6.6 KiB
TypeScript
import { AuthStorage, ModelRegistry } from "@mariozechner/pi-coding-agent";
|
|
import { getUserName as getAlphaUserName, isLoggedIn as isAlphaLoggedIn } from "@companion-ai/alpha-hub/lib";
|
|
|
|
import { formatPiWebAccessDoctorLines, getPiWebAccessStatus } from "../pi/web-access.js";
|
|
import { BROWSER_FALLBACK_PATHS, PANDOC_FALLBACK_PATHS, resolveExecutable } from "../system/executables.js";
|
|
import { readJson } from "../pi/settings.js";
|
|
import { validatePiInstallation } from "../pi/runtime.js";
|
|
import { printInfo, printPanel, printSection } from "../ui/terminal.js";
|
|
import { getCurrentModelSpec } from "../model/commands.js";
|
|
import { buildModelStatusSnapshotFromRecords, getAvailableModelRecords, getSupportedModelRecords } from "../model/catalog.js";
|
|
|
|
export type DoctorOptions = {
|
|
settingsPath: string;
|
|
authPath: string;
|
|
sessionDir: string;
|
|
workingDir: string;
|
|
appRoot: string;
|
|
};
|
|
|
|
export type FeynmanStatusSnapshot = {
|
|
model?: string;
|
|
modelValid: boolean;
|
|
recommendedModel?: string;
|
|
recommendedModelReason?: string;
|
|
authenticatedModelCount: number;
|
|
authenticatedProviderCount: number;
|
|
modelGuidance: string[];
|
|
alphaLoggedIn: boolean;
|
|
alphaUser?: string;
|
|
webRouteLabel: string;
|
|
previewConfigured: boolean;
|
|
sessionDir: string;
|
|
pandocReady: boolean;
|
|
browserReady: boolean;
|
|
piReady: boolean;
|
|
missingPiBits: string[];
|
|
};
|
|
|
|
export function collectStatusSnapshot(options: DoctorOptions): FeynmanStatusSnapshot {
|
|
const pandocPath = resolveExecutable("pandoc", PANDOC_FALLBACK_PATHS);
|
|
const browserPath = process.env.PUPPETEER_EXECUTABLE_PATH ?? resolveExecutable("google-chrome", BROWSER_FALLBACK_PATHS);
|
|
const missingPiBits = validatePiInstallation(options.appRoot);
|
|
const webStatus = getPiWebAccessStatus();
|
|
const modelStatus = buildModelStatusSnapshotFromRecords(
|
|
getSupportedModelRecords(options.authPath),
|
|
getAvailableModelRecords(options.authPath),
|
|
getCurrentModelSpec(options.settingsPath),
|
|
);
|
|
|
|
return {
|
|
model: modelStatus.current,
|
|
modelValid: modelStatus.currentValid,
|
|
recommendedModel: modelStatus.recommended,
|
|
recommendedModelReason: modelStatus.recommendationReason,
|
|
authenticatedModelCount: modelStatus.availableModels.length,
|
|
authenticatedProviderCount: modelStatus.providers.filter((provider) => provider.configured).length,
|
|
modelGuidance: modelStatus.guidance,
|
|
alphaLoggedIn: isAlphaLoggedIn(),
|
|
alphaUser: isAlphaLoggedIn() ? getAlphaUserName() ?? undefined : undefined,
|
|
webRouteLabel: webStatus.routeLabel,
|
|
previewConfigured: Boolean(pandocPath),
|
|
sessionDir: options.sessionDir,
|
|
pandocReady: Boolean(pandocPath),
|
|
browserReady: Boolean(browserPath),
|
|
piReady: missingPiBits.length === 0,
|
|
missingPiBits,
|
|
};
|
|
}
|
|
|
|
export function runStatus(options: DoctorOptions): void {
|
|
const snapshot = collectStatusSnapshot(options);
|
|
printPanel("Feynman Status", [
|
|
"Current setup summary for the research shell.",
|
|
]);
|
|
printSection("Core");
|
|
printInfo(`Model: ${snapshot.model ?? "not configured"}`);
|
|
printInfo(`Model valid: ${snapshot.modelValid ? "yes" : "no"}`);
|
|
printInfo(`Authenticated models: ${snapshot.authenticatedModelCount}`);
|
|
printInfo(`Authenticated providers: ${snapshot.authenticatedProviderCount}`);
|
|
printInfo(`Recommended model: ${snapshot.recommendedModel ?? "not available"}`);
|
|
printInfo(`alphaXiv: ${snapshot.alphaLoggedIn ? snapshot.alphaUser ?? "configured" : "not configured"}`);
|
|
printInfo(`Web access: pi-web-access (${snapshot.webRouteLabel})`);
|
|
printInfo(`Preview: ${snapshot.previewConfigured ? "configured" : "not configured"}`);
|
|
|
|
printSection("Paths");
|
|
printInfo(`Sessions: ${snapshot.sessionDir}`);
|
|
|
|
printSection("Runtime");
|
|
printInfo(`Pi runtime: ${snapshot.piReady ? "ready" : "missing files"}`);
|
|
printInfo(`Pandoc: ${snapshot.pandocReady ? "ready" : "missing"}`);
|
|
printInfo(`Browser preview: ${snapshot.browserReady ? "ready" : "missing"}`);
|
|
if (snapshot.missingPiBits.length > 0) {
|
|
for (const entry of snapshot.missingPiBits) {
|
|
printInfo(` missing: ${entry}`);
|
|
}
|
|
}
|
|
if (snapshot.modelGuidance.length > 0) {
|
|
printSection("Next Steps");
|
|
for (const line of snapshot.modelGuidance) {
|
|
printInfo(line);
|
|
}
|
|
}
|
|
}
|
|
|
|
export function runDoctor(options: DoctorOptions): void {
|
|
const settings = readJson(options.settingsPath);
|
|
const modelRegistry = new ModelRegistry(AuthStorage.create(options.authPath));
|
|
const availableModels = modelRegistry.getAvailable();
|
|
const pandocPath = resolveExecutable("pandoc", PANDOC_FALLBACK_PATHS);
|
|
const browserPath = process.env.PUPPETEER_EXECUTABLE_PATH ?? resolveExecutable("google-chrome", BROWSER_FALLBACK_PATHS);
|
|
const missingPiBits = validatePiInstallation(options.appRoot);
|
|
|
|
printPanel("Feynman Doctor", [
|
|
"Checks config, auth, runtime wiring, and preview dependencies.",
|
|
]);
|
|
console.log(`working dir: ${options.workingDir}`);
|
|
console.log(`session dir: ${options.sessionDir}`);
|
|
console.log("");
|
|
console.log(`alphaXiv auth: ${isAlphaLoggedIn() ? "ok" : "missing"}`);
|
|
if (isAlphaLoggedIn()) {
|
|
const name = getAlphaUserName();
|
|
if (name) {
|
|
console.log(` user: ${name}`);
|
|
}
|
|
}
|
|
console.log(`models available: ${availableModels.length}`);
|
|
if (availableModels.length > 0) {
|
|
const sample = availableModels
|
|
.slice(0, 6)
|
|
.map((model) => `${model.provider}/${model.id}`)
|
|
.join(", ");
|
|
console.log(` sample: ${sample}`);
|
|
}
|
|
console.log(
|
|
`default model: ${typeof settings.defaultProvider === "string" && typeof settings.defaultModel === "string"
|
|
? `${settings.defaultProvider}/${settings.defaultModel}`
|
|
: "not set"}`,
|
|
);
|
|
const modelStatus = collectStatusSnapshot(options);
|
|
console.log(`default model valid: ${modelStatus.modelValid ? "yes" : "no"}`);
|
|
console.log(`authenticated providers: ${modelStatus.authenticatedProviderCount}`);
|
|
console.log(`authenticated models: ${modelStatus.authenticatedModelCount}`);
|
|
console.log(`recommended model: ${modelStatus.recommendedModel ?? "not available"}`);
|
|
if (modelStatus.recommendedModelReason) {
|
|
console.log(` why: ${modelStatus.recommendedModelReason}`);
|
|
}
|
|
console.log(`pandoc: ${pandocPath ?? "missing"}`);
|
|
console.log(`browser preview runtime: ${browserPath ?? "missing"}`);
|
|
for (const line of formatPiWebAccessDoctorLines()) {
|
|
console.log(line);
|
|
}
|
|
console.log(`quiet startup: ${settings.quietStartup === true ? "enabled" : "disabled"}`);
|
|
console.log(`theme: ${typeof settings.theme === "string" ? settings.theme : "not set"}`);
|
|
if (missingPiBits.length > 0) {
|
|
console.log("pi runtime: missing files");
|
|
for (const entry of missingPiBits) {
|
|
console.log(` ${entry}`);
|
|
}
|
|
} else {
|
|
console.log("pi runtime: ok");
|
|
}
|
|
for (const line of modelStatus.modelGuidance) {
|
|
console.log(`next step: ${line}`);
|
|
}
|
|
console.log("setup hint: feynman setup");
|
|
}
|