Fix packaged runtime startup and version flag

This commit is contained in:
Advait Paliwal
2026-03-24 19:32:10 -07:00
parent cd85e875df
commit 79e14dd79d
3 changed files with 46 additions and 26 deletions

View File

@@ -33,7 +33,7 @@
"build": "tsc -p tsconfig.build.json", "build": "tsc -p tsconfig.build.json",
"build:native-bundle": "node ./scripts/build-native-bundle.mjs", "build:native-bundle": "node ./scripts/build-native-bundle.mjs",
"dev": "tsx src/index.ts", "dev": "tsx src/index.ts",
"prepack": "node ./scripts/prepare-runtime-workspace.mjs", "prepack": "npm run build && node ./scripts/prepare-runtime-workspace.mjs",
"start": "tsx src/index.ts", "start": "tsx src/index.ts",
"start:dist": "node ./bin/feynman.js", "start:dist": "node ./bin/feynman.js",
"test": "node --import tsx --test --test-concurrency=1 tests/*.test.ts", "test": "node --import tsx --test --test-concurrency=1 tests/*.test.ts",

View File

@@ -1,28 +1,40 @@
import { spawnSync } from "node:child_process"; import { spawnSync } from "node:child_process";
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { createRequire } from "node:module";
import { dirname, resolve } from "node:path"; import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url"; import { fileURLToPath } from "node:url";
import { FEYNMAN_LOGO_HTML } from "../logo.mjs"; import { FEYNMAN_LOGO_HTML } from "../logo.mjs";
const here = dirname(fileURLToPath(import.meta.url)); const here = dirname(fileURLToPath(import.meta.url));
const appRoot = resolve(here, ".."); const appRoot = resolve(here, "..");
const appRequire = createRequire(resolve(appRoot, "package.json"));
const isGlobalInstall = process.env.npm_config_global === "true" || process.env.npm_config_location === "global"; const isGlobalInstall = process.env.npm_config_global === "true" || process.env.npm_config_location === "global";
function findNodeModules() {
let dir = appRoot;
while (dir !== dirname(dir)) {
const nm = resolve(dir, "node_modules");
if (existsSync(nm)) return nm;
dir = dirname(dir);
}
return resolve(appRoot, "node_modules");
}
const nodeModules = findNodeModules();
function findPackageRoot(packageName) { function findPackageRoot(packageName) {
const candidate = resolve(nodeModules, packageName); const segments = packageName.split("/");
if (existsSync(resolve(candidate, "package.json"))) return candidate; let current = appRoot;
while (current !== dirname(current)) {
for (const candidate of [resolve(current, "node_modules", ...segments), resolve(current, ...segments)]) {
if (existsSync(resolve(candidate, "package.json"))) {
return candidate;
}
}
current = dirname(current);
}
for (const spec of [`${packageName}/dist/index.js`, `${packageName}/dist/cli.js`, packageName]) {
try {
let current = dirname(appRequire.resolve(spec));
while (current !== dirname(current)) {
if (existsSync(resolve(current, "package.json"))) {
return current;
}
current = dirname(current);
}
} catch {
continue;
}
}
return null; return null;
} }
@@ -31,15 +43,14 @@ const piTuiRoot = findPackageRoot("@mariozechner/pi-tui");
const piAiRoot = findPackageRoot("@mariozechner/pi-ai"); const piAiRoot = findPackageRoot("@mariozechner/pi-ai");
if (!piPackageRoot) { if (!piPackageRoot) {
console.warn("[feynman] pi-coding-agent not found, skipping patches"); console.warn("[feynman] pi-coding-agent not found, skipping Pi patches");
process.exit(0);
} }
const packageJsonPath = resolve(piPackageRoot, "package.json"); const packageJsonPath = piPackageRoot ? resolve(piPackageRoot, "package.json") : null;
const cliPath = resolve(piPackageRoot, "dist", "cli.js"); const cliPath = piPackageRoot ? resolve(piPackageRoot, "dist", "cli.js") : null;
const bunCliPath = resolve(piPackageRoot, "dist", "bun", "cli.js"); const bunCliPath = piPackageRoot ? resolve(piPackageRoot, "dist", "bun", "cli.js") : null;
const interactiveModePath = resolve(piPackageRoot, "dist", "modes", "interactive", "interactive-mode.js"); const interactiveModePath = piPackageRoot ? resolve(piPackageRoot, "dist", "modes", "interactive", "interactive-mode.js") : null;
const interactiveThemePath = resolve(piPackageRoot, "dist", "modes", "interactive", "theme", "theme.js"); const interactiveThemePath = piPackageRoot ? resolve(piPackageRoot, "dist", "modes", "interactive", "theme", "theme.js") : null;
const editorPath = piTuiRoot ? resolve(piTuiRoot, "dist", "components", "editor.js") : null; const editorPath = piTuiRoot ? resolve(piTuiRoot, "dist", "components", "editor.js") : null;
const workspaceRoot = resolve(appRoot, ".feynman", "npm", "node_modules"); const workspaceRoot = resolve(appRoot, ".feynman", "npm", "node_modules");
const webAccessPath = resolve(workspaceRoot, "pi-web-access", "index.ts"); const webAccessPath = resolve(workspaceRoot, "pi-web-access", "index.ts");
@@ -219,7 +230,7 @@ function ensurePandoc() {
ensurePandoc(); ensurePandoc();
if (existsSync(packageJsonPath)) { if (packageJsonPath && existsSync(packageJsonPath)) {
const pkg = JSON.parse(readFileSync(packageJsonPath, "utf8")); const pkg = JSON.parse(readFileSync(packageJsonPath, "utf8"));
if (pkg.piConfig?.name !== "feynman" || pkg.piConfig?.configDir !== ".feynman") { if (pkg.piConfig?.name !== "feynman" || pkg.piConfig?.configDir !== ".feynman") {
pkg.piConfig = { pkg.piConfig = {
@@ -231,7 +242,7 @@ if (existsSync(packageJsonPath)) {
} }
} }
for (const entryPath of [cliPath, bunCliPath]) { for (const entryPath of [cliPath, bunCliPath].filter(Boolean)) {
if (!existsSync(entryPath)) { if (!existsSync(entryPath)) {
continue; continue;
} }
@@ -242,7 +253,7 @@ for (const entryPath of [cliPath, bunCliPath]) {
} }
} }
if (existsSync(interactiveModePath)) { if (interactiveModePath && existsSync(interactiveModePath)) {
const interactiveModeSource = readFileSync(interactiveModePath, "utf8"); const interactiveModeSource = readFileSync(interactiveModePath, "utf8");
if (interactiveModeSource.includes("`π - ${sessionName} - ${cwdBasename}`")) { if (interactiveModeSource.includes("`π - ${sessionName} - ${cwdBasename}`")) {
writeFileSync( writeFileSync(
@@ -255,7 +266,7 @@ if (existsSync(interactiveModePath)) {
} }
} }
if (existsSync(interactiveThemePath)) { if (interactiveThemePath && existsSync(interactiveThemePath)) {
let themeSource = readFileSync(interactiveThemePath, "utf8"); let themeSource = readFileSync(interactiveThemePath, "utf8");
const desiredGetEditorTheme = [ const desiredGetEditorTheme = [
"export function getEditorTheme() {", "export function getEditorTheme() {",

View File

@@ -293,6 +293,7 @@ export async function main(): Promise<void> {
cwd: { type: "string" }, cwd: { type: "string" },
doctor: { type: "boolean" }, doctor: { type: "boolean" },
help: { type: "boolean" }, help: { type: "boolean" },
version: { type: "boolean" },
"alpha-login": { type: "boolean" }, "alpha-login": { type: "boolean" },
"alpha-logout": { type: "boolean" }, "alpha-logout": { type: "boolean" },
"alpha-status": { type: "boolean" }, "alpha-status": { type: "boolean" },
@@ -310,6 +311,14 @@ export async function main(): Promise<void> {
return; return;
} }
if (values.version) {
if (feynmanVersion) {
console.log(feynmanVersion);
return;
}
throw new Error("Unable to determine the installed Feynman version.");
}
const workingDir = resolve(values.cwd ?? process.cwd()); const workingDir = resolve(values.cwd ?? process.cwd());
const sessionDir = resolve(values["session-dir"] ?? getDefaultSessionDir(feynmanHome)); const sessionDir = resolve(values["session-dir"] ?? getDefaultSessionDir(feynmanHome));
const feynmanSettingsPath = resolve(feynmanAgentDir, "settings.json"); const feynmanSettingsPath = resolve(feynmanAgentDir, "settings.json");