diff --git a/.feynman/settings.json b/.feynman/settings.json index fda575b..257d3e8 100644 --- a/.feynman/settings.json +++ b/.feynman/settings.json @@ -9,7 +9,9 @@ "npm:pi-mermaid", "npm:@aliou/pi-processes", "npm:pi-zotero", + "npm:@kaiserlich-dev/pi-session-search", "npm:pi-schedule-prompt", + "npm:@samfp/pi-memory", "npm:@tmustier/pi-ralph-wiggum" ], "quietStartup": true, diff --git a/extensions/research-tools/shared.ts b/extensions/research-tools/shared.ts index f4678c6..2157753 100644 --- a/extensions/research-tools/shared.ts +++ b/extensions/research-tools/shared.ts @@ -14,14 +14,7 @@ export const FEYNMAN_VERSION = (() => { } })(); -export const FEYNMAN_AGENT_LOGO = [ - "███████╗███████╗██╗ ██╗███╗ ██╗███╗ ███╗ █████╗ ███╗ ██╗", - "██╔════╝██╔════╝╚██╗ ██╔╝████╗ ██║████╗ ████║██╔══██╗████╗ ██║", - "█████╗ █████╗ ╚████╔╝ ██╔██╗ ██║██╔████╔██║███████║██╔██╗ ██║", - "██╔══╝ ██╔══╝ ╚██╔╝ ██║╚██╗██║██║╚██╔╝██║██╔══██║██║╚██╗██║", - "██║ ███████╗ ██║ ██║ ╚████║██║ ╚═╝ ██║██║ ██║██║ ╚████║", - "╚═╝ ╚══════╝ ╚═╝ ╚═╝ ╚═══╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝", -]; +export { FEYNMAN_ASCII_LOGO as FEYNMAN_AGENT_LOGO } from "../../logo.mjs"; export const FEYNMAN_RESEARCH_TOOLS = [ "alpha_search", diff --git a/logo.d.mts b/logo.d.mts new file mode 100644 index 0000000..1552567 --- /dev/null +++ b/logo.d.mts @@ -0,0 +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; diff --git a/logo.mjs b/logo.mjs new file mode 100644 index 0000000..29b9fef --- /dev/null +++ b/logo.mjs @@ -0,0 +1,12 @@ +export const FEYNMAN_ASCII_LOGO = [ + "███████╗███████╗██╗ ██╗███╗ ██╗███╗ ███╗ █████╗ ███╗ ██╗", + "██╔════╝██╔════╝╚██╗ ██╔╝████╗ ██║████╗ ████║██╔══██╗████╗ ██║", + "█████╗ █████╗ ╚████╔╝ ██╔██╗ ██║██╔████╔██║███████║██╔██╗ ██║", + "██╔══╝ ██╔══╝ ╚██╔╝ ██║╚██╗██║██║╚██╔╝██║██╔══██║██║╚██╗██║", + "██║ ███████╗ ██║ ██║ ╚████║██║ ╚═╝ ██║██║ ██║██║ ╚████║", + "╚═╝ ╚══════╝ ╚═╝ ╚═╝ ╚═══╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝", +]; + +export const FEYNMAN_ASCII_LOGO_TEXT = FEYNMAN_ASCII_LOGO.join("\n"); + +export const FEYNMAN_ASCII_LOGO_HTML = `
${FEYNMAN_ASCII_LOGO_TEXT}`;
diff --git a/package-lock.json b/package-lock.json
index 3834ec2..1674b5d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@companion-ai/feynman",
- "version": "0.2.6",
+ "version": "0.2.7",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@companion-ai/feynman",
- "version": "0.2.6",
+ "version": "0.2.7",
"hasInstallScript": true,
"dependencies": {
"@companion-ai/alpha-hub": "^0.1.2",
diff --git a/package.json b/package.json
index b6a3f3b..9ad73d1 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@companion-ai/feynman",
- "version": "0.2.6",
+ "version": "0.2.7",
"description": "Research-first CLI agent built on Pi and alphaXiv",
"type": "module",
"engines": {
diff --git a/scripts/patch-embedded-pi.mjs b/scripts/patch-embedded-pi.mjs
index 2d74588..cc0c657 100644
--- a/scripts/patch-embedded-pi.mjs
+++ b/scripts/patch-embedded-pi.mjs
@@ -2,6 +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";
const here = dirname(fileURLToPath(import.meta.url));
const appRoot = resolve(here, "..");
@@ -90,14 +91,27 @@ function ensurePackageWorkspace() {
"utf8",
);
- console.log("[feynman] installing research packages...");
- const result = spawnSync("npm", ["install", "--prefer-offline", "--no-audit", "--no-fund", "--prefix", workspaceDir, ...packageSpecs], {
- stdio: "inherit",
+ const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
+ let frame = 0;
+ const start = Date.now();
+ const spinner = setInterval(() => {
+ const elapsed = Math.round((Date.now() - start) / 1000);
+ process.stderr.write(`\r${frames[frame++ % frames.length]} setting up feynman... ${elapsed}s`);
+ }, 80);
+
+ const result = spawnSync("npm", ["install", "--prefer-offline", "--no-audit", "--no-fund", "--loglevel", "error", "--prefix", workspaceDir, ...packageSpecs], {
+ stdio: ["ignore", "ignore", "pipe"],
timeout: 300000,
});
+ clearInterval(spinner);
+ const elapsed = Math.round((Date.now() - start) / 1000);
+
if (result.status !== 0) {
- console.warn("[feynman] warning: package install failed, Pi will retry on first launch");
+ process.stderr.write(`\r✗ setup failed (${elapsed}s)\n`);
+ if (result.stderr?.length) process.stderr.write(result.stderr);
+ } else {
+ process.stderr.write(`\r✓ feynman ready (${elapsed}s)\n`);
}
}
@@ -351,12 +365,33 @@ if (oauthPagePath && existsSync(oauthPagePath)) {
let source = readFileSync(oauthPagePath, "utf8");
const piLogo = 'const LOGO_SVG = ``;';
if (source.includes(piLogo)) {
- const feynmanLogo = 'const LOGO_SVG = `feynman`;';
+ const feynmanLogo = `const LOGO_SVG = \`${FEYNMAN_ASCII_LOGO_HTML}\`;`;
source = source.replace(piLogo, feynmanLogo);
writeFileSync(oauthPagePath, source, "utf8");
}
}
+const alphaHubAuthPath = findPackageRoot("@companion-ai/alpha-hub")
+ ? resolve(findPackageRoot("@companion-ai/alpha-hub"), "src", "lib", "auth.js")
+ : null;
+
+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.
'`; + if (source.includes(oldSuccess)) { + source = source.replace(oldSuccess, `'${successPage}'`); + } + if (source.includes(oldError)) { + source = source.replace(oldError, `'${errorPage}'`); + } + writeFileSync(alphaHubAuthPath, source, "utf8"); +} + if (existsSync(piMemoryPath)) { let source = readFileSync(piMemoryPath, "utf8"); const memoryOriginal = 'const MEMORY_DIR = join(homedir(), ".pi", "memory");'; diff --git a/src/pi/package-presets.ts b/src/pi/package-presets.ts index fa14a95..de37138 100644 --- a/src/pi/package-presets.ts +++ b/src/pi/package-presets.ts @@ -10,7 +10,9 @@ export const CORE_PACKAGE_SOURCES = [ "npm:pi-mermaid", "npm:@aliou/pi-processes", "npm:pi-zotero", + "npm:@kaiserlich-dev/pi-session-search", "npm:pi-schedule-prompt", + "npm:@samfp/pi-memory", "npm:@tmustier/pi-ralph-wiggum", ] as const; @@ -19,25 +21,11 @@ export const OPTIONAL_PACKAGE_PRESETS = { description: "Interactive Glimpse UI widgets.", sources: ["npm:pi-generative-ui"], }, - memory: { - description: "Cross-session memory and preference recall.", - sources: ["npm:@samfp/pi-memory"], - }, - "session-search": { - description: "Indexed session recall with SQLite-backed search.", - sources: ["npm:@kaiserlich-dev/pi-session-search"], - }, - "all-extras": { - description: "Install all optional packages.", - sources: ["npm:pi-generative-ui", "npm:@samfp/pi-memory", "npm:@kaiserlich-dev/pi-session-search"], - }, } as const; const LEGACY_DEFAULT_PACKAGE_SOURCES = [ ...CORE_PACKAGE_SOURCES, "npm:pi-generative-ui", - "npm:@kaiserlich-dev/pi-session-search", - "npm:@samfp/pi-memory", ] as const; export type OptionalPackagePresetName = keyof typeof OPTIONAL_PACKAGE_PRESETS; @@ -66,9 +54,6 @@ export function getOptionalPackagePresetSources(name: string): string[] | undefi if (normalized === "ui") { return [...OPTIONAL_PACKAGE_PRESETS["generative-ui"].sources]; } - if (normalized === "search") { - return [...OPTIONAL_PACKAGE_PRESETS["session-search"].sources]; - } const preset = OPTIONAL_PACKAGE_PRESETS[normalized as OptionalPackagePresetName]; return preset ? [...preset.sources] : undefined; diff --git a/tests/pi-settings.test.ts b/tests/pi-settings.test.ts index 8461e62..f33de48 100644 --- a/tests/pi-settings.test.ts +++ b/tests/pi-settings.test.ts @@ -49,8 +49,6 @@ test("normalizeFeynmanSettings prunes the legacy slow default package set", () = packages: [ ...CORE_PACKAGE_SOURCES, "npm:pi-generative-ui", - "npm:@kaiserlich-dev/pi-session-search", - "npm:@samfp/pi-memory", ], }, null, @@ -68,8 +66,8 @@ test("normalizeFeynmanSettings prunes the legacy slow default package set", () = }); test("optional package presets map friendly aliases", () => { - assert.deepEqual(getOptionalPackagePresetSources("memory"), ["npm:@samfp/pi-memory"]); + assert.deepEqual(getOptionalPackagePresetSources("memory"), undefined); assert.deepEqual(getOptionalPackagePresetSources("ui"), ["npm:pi-generative-ui"]); - assert.deepEqual(getOptionalPackagePresetSources("search"), ["npm:@kaiserlich-dev/pi-session-search"]); + assert.deepEqual(getOptionalPackagePresetSources("search"), undefined); assert.equal(shouldPruneLegacyDefaultPackages(["npm:custom"]), false); }); diff --git a/website/src/components/AsciiLogo.astro b/website/src/components/AsciiLogo.astro new file mode 100644 index 0000000..4eebd0d --- /dev/null +++ b/website/src/components/AsciiLogo.astro @@ -0,0 +1,26 @@ +--- +interface Props { + class?: string; + size?: 'nav' | 'hero'; +} + +const { class: className = '', size = 'hero' } = Astro.props; + +const sizeClasses = size === 'nav' + ? 'text-[4px] sm:text-[5px]' + : 'text-[6px] sm:text-[8px] md:text-[10px]'; +--- + +███████╗███████╗██╗ ██╗███╗ ██╗███╗ ███╗ █████╗ ███╗ ██╗ +██╔════╝██╔════╝╚██╗ ██╔╝████╗ ██║████╗ ████║██╔══██╗████╗ ██║ +█████╗ █████╗ ╚████╔╝ ██╔██╗ ██║██╔████╔██║███████║██╔██╗ ██║ +██╔══╝ ██╔══╝ ╚██╔╝ ██║╚██╗██║██║╚██╔╝██║██╔══██║██║╚██╗██║ +██║ ███████╗ ██║ ██║ ╚████║██║ ╚═╝ ██║██║ ██║██║ ╚████║ +╚═╝ ╚══════╝ ╚═╝ ╚═╝ ╚═══╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝diff --git a/website/src/components/Nav.astro b/website/src/components/Nav.astro index 184610a..cdd99d2 100644 --- a/website/src/components/Nav.astro +++ b/website/src/components/Nav.astro @@ -1,5 +1,6 @@ --- import ThemeToggle from './ThemeToggle.astro'; +import AsciiLogo from './AsciiLogo.astro'; interface Props { active?: 'home' | 'docs'; @@ -10,7 +11,9 @@ const { active = 'home' } = Astro.props;