diff --git a/CHANGELOG.md b/CHANGELOG.md index e96d9a0..6704554 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -259,6 +259,15 @@ Use this file to track chronology, not release notes. Keep entries short, factua - Blockers: I did not rerun a full broad deepresearch workflow end-to-end after this prompt-only hardening because those runs are materially longer and more expensive than the narrow reproductions already used to isolate the earlier deadlocks. - Next: Commit and push the prompt hardening, then, if needed, add a deterministic wrapper around final artifact promotion instead of relying only on prompt adherence. +### 2026-04-14 09:30 PDT — wsl-login-and-uninstall-docs-pass + +- Objective: Fix the remaining WSL setup blocker and close the last actionable support issue instead of leaving the tracker open after the earlier workflow/model fixes. +- Changed: Added a dedicated alpha-hub auth patch helper and tests; extended the alphaXiv login patch so WSL uses `wslview` when available and falls back to `cmd.exe /c start`, while also printing the auth URL explicitly for manual copy/paste if browser launch still fails; documented standalone uninstall steps in `README.md` and `website/src/content/docs/getting-started/installation.md`. +- Verified: Added regression tests for the alpha-hub auth patch, reran `npm test`, `npm run typecheck`, and `npm run build`, and smoke-checked the patched alpha-hub source rewrite to confirm it injects both the WSL browser path and the explicit auth URL logging. +- Failed / learned: This repo can patch alpha-hub's login UX reliably, but it still does not ship a destructive `feynman uninstall` command; the practical fix for the support issue is documented uninstall steps rather than a rushed cross-platform remover. +- Blockers: I did not run a true WSL shell here, so the WSL fix is validated by the deterministic source patch plus tests rather than an actual Windows-hosted browser-launch repro. +- Next: Push the WSL/login pass and close the stale issues and PRs that are already superseded by `main`. + ### 2026-04-12 13:20 PDT — capital-france (citation verification brief) - Objective: Verify citations in the capital-of-France draft and produce a cited verifier brief. diff --git a/README.md b/README.md index 2d5aaa8..9d9d295 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,8 @@ The installer downloads a standalone native bundle with its own Node.js runtime. To upgrade the standalone app later, rerun the installer. `feynman update` only refreshes installed Pi packages inside Feynman's environment; it does not replace the standalone runtime bundle itself. +To uninstall the standalone app, remove the launcher and runtime bundle, then optionally remove `~/.feynman` if you also want to delete settings, auth, and sessions. See the installation guide for platform-specific paths. + Local models are supported through the custom-provider flow. For Ollama, run `feynman setup`, choose `Custom provider (baseUrl + API key)`, use `openai-completions`, and point it at `http://localhost:11434/v1`. ### Skills Only diff --git a/scripts/lib/alpha-hub-auth-patch.d.mts b/scripts/lib/alpha-hub-auth-patch.d.mts new file mode 100644 index 0000000..f4592f2 --- /dev/null +++ b/scripts/lib/alpha-hub-auth-patch.d.mts @@ -0,0 +1 @@ +export declare function patchAlphaHubAuthSource(source: string): string; diff --git a/scripts/lib/alpha-hub-auth-patch.mjs b/scripts/lib/alpha-hub-auth-patch.mjs new file mode 100644 index 0000000..b282980 --- /dev/null +++ b/scripts/lib/alpha-hub-auth-patch.mjs @@ -0,0 +1,66 @@ +const LEGACY_SUCCESS_HTML = "'
You can close this tab.
'"; +const LEGACY_ERROR_HTML = "'You can close this tab.
'"; + +const bodyAttr = 'style="font-family:system-ui,sans-serif;text-align:center;padding-top:20vh;background:#050a08;color:#f0f5f2"'; +const logo = 'You can close this tab.
'`; +const FEYNMAN_ERROR_HTML = `'${logo}You can close this tab.
'`; + +const CURRENT_OPEN_BROWSER = [ + "function openBrowser(url) {", + " try {", + " const plat = platform();", + " if (plat === 'darwin') execSync(`open \"${url}\"`);", + " else if (plat === 'linux') execSync(`xdg-open \"${url}\"`);", + " else if (plat === 'win32') execSync(`start \"\" \"${url}\"`);", + " } catch {}", + "}", +].join("\n"); + +const PATCHED_OPEN_BROWSER = [ + "function openBrowser(url) {", + " try {", + " const plat = platform();", + " const isWsl = plat === 'linux' && (Boolean(process.env.WSL_DISTRO_NAME) || Boolean(process.env.WSL_INTEROP));", + " if (plat === 'darwin') execSync(`open \"${url}\"`);", + " else if (isWsl) {", + " try {", + " execSync(`wslview \"${url}\"`);", + " } catch {", + " execSync(`cmd.exe /c start \"\" \"${url}\"`);", + " }", + " }", + " else if (plat === 'linux') execSync(`xdg-open \"${url}\"`);", + " else if (plat === 'win32') execSync(`cmd /c start \"\" \"${url}\"`);", + " } catch {}", + "}", +].join("\n"); + +const LEGACY_WIN_OPEN = "else if (plat === 'win32') execSync(`start \"${url}\"`);"; +const FIXED_WIN_OPEN = "else if (plat === 'win32') execSync(`cmd /c start \"\" \"${url}\"`);"; + +const OPEN_BROWSER_LOG = "process.stderr.write('Opening browser for alphaXiv login...\\n');"; +const OPEN_BROWSER_LOG_WITH_URL = "process.stderr.write(`Opening browser for alphaXiv login...\\nAuth URL: ${authUrl.toString()}\\n`);"; + +export function patchAlphaHubAuthSource(source) { + let patched = source; + + if (patched.includes(LEGACY_SUCCESS_HTML)) { + patched = patched.replace(LEGACY_SUCCESS_HTML, FEYNMAN_SUCCESS_HTML); + } + if (patched.includes(LEGACY_ERROR_HTML)) { + patched = patched.replace(LEGACY_ERROR_HTML, FEYNMAN_ERROR_HTML); + } + if (patched.includes(CURRENT_OPEN_BROWSER)) { + patched = patched.replace(CURRENT_OPEN_BROWSER, PATCHED_OPEN_BROWSER); + } + if (patched.includes(LEGACY_WIN_OPEN)) { + patched = patched.replace(LEGACY_WIN_OPEN, FIXED_WIN_OPEN); + } + if (patched.includes(OPEN_BROWSER_LOG)) { + patched = patched.replace(OPEN_BROWSER_LOG, OPEN_BROWSER_LOG_WITH_URL); + } + + return patched; +} diff --git a/scripts/patch-embedded-pi.mjs b/scripts/patch-embedded-pi.mjs index 2b18c2e..8d1b892 100644 --- a/scripts/patch-embedded-pi.mjs +++ b/scripts/patch-embedded-pi.mjs @@ -5,6 +5,7 @@ import { homedir } from "node:os"; import { dirname, resolve } from "node:path"; import { fileURLToPath } from "node:url"; import { FEYNMAN_LOGO_HTML } from "../logo.mjs"; +import { patchAlphaHubAuthSource } from "./lib/alpha-hub-auth-patch.mjs"; import { patchPiExtensionLoaderSource } from "./lib/pi-extension-loader-patch.mjs"; import { patchPiGoogleLegacySchemaSource } from "./lib/pi-google-legacy-schema-patch.mjs"; import { PI_WEB_ACCESS_PATCH_TARGETS, patchPiWebAccessSource } from "./lib/pi-web-access-patch.mjs"; @@ -620,25 +621,11 @@ const alphaHubAuthPath = findPackageRoot("@companion-ai/alpha-hub") : null; if (alphaHubAuthPath && existsSync(alphaHubAuthPath)) { - let source = readFileSync(alphaHubAuthPath, "utf8"); - const oldSuccess = "'You can close this tab.
'"; - const oldError = "'You can close this tab.
'"; - const bodyAttr = `style="font-family:system-ui,sans-serif;text-align:center;padding-top:20vh;background:#050a08;color:#f0f5f2"`; - const logo = `You can close this tab.
'`; - const newError = `'${logo}You can close this tab.
'`; - if (source.includes(oldSuccess)) { - source = source.replace(oldSuccess, newSuccess); + const source = readFileSync(alphaHubAuthPath, "utf8"); + const patched = patchAlphaHubAuthSource(source); + if (patched !== source) { + writeFileSync(alphaHubAuthPath, patched, "utf8"); } - if (source.includes(oldError)) { - source = source.replace(oldError, newError); - } - const brokenWinOpen = "else if (plat === 'win32') execSync(`start \"${url}\"`);"; - const fixedWinOpen = "else if (plat === 'win32') execSync(`cmd /c start \"\" \"${url}\"`);"; - if (source.includes(brokenWinOpen)) { - source = source.replace(brokenWinOpen, fixedWinOpen); - } - writeFileSync(alphaHubAuthPath, source, "utf8"); } if (existsSync(piMemoryPath)) { diff --git a/tests/alpha-hub-auth-patch.test.ts b/tests/alpha-hub-auth-patch.test.ts new file mode 100644 index 0000000..2e90bd3 --- /dev/null +++ b/tests/alpha-hub-auth-patch.test.ts @@ -0,0 +1,51 @@ +import test from "node:test"; +import assert from "node:assert/strict"; + +import { patchAlphaHubAuthSource } from "../scripts/lib/alpha-hub-auth-patch.mjs"; + +test("patchAlphaHubAuthSource fixes browser open logic for WSL and Windows", () => { + const input = [ + "function openBrowser(url) {", + " try {", + " const plat = platform();", + " if (plat === 'darwin') execSync(`open \"${url}\"`);", + " else if (plat === 'linux') execSync(`xdg-open \"${url}\"`);", + " else if (plat === 'win32') execSync(`start \"\" \"${url}\"`);", + " } catch {}", + "}", + ].join("\n"); + + const patched = patchAlphaHubAuthSource(input); + + assert.match(patched, /const isWsl = plat === 'linux'/); + assert.match(patched, /wslview/); + assert.match(patched, /cmd\.exe \/c start/); + assert.match(patched, /cmd \/c start/); +}); + +test("patchAlphaHubAuthSource includes the auth URL in login output", () => { + const input = "process.stderr.write('Opening browser for alphaXiv login...\\n');"; + + const patched = patchAlphaHubAuthSource(input); + + assert.match(patched, /Auth URL: \$\{authUrl\.toString\(\)\}/); +}); + +test("patchAlphaHubAuthSource is idempotent", () => { + const input = [ + "function openBrowser(url) {", + " try {", + " const plat = platform();", + " if (plat === 'darwin') execSync(`open \"${url}\"`);", + " else if (plat === 'linux') execSync(`xdg-open \"${url}\"`);", + " else if (plat === 'win32') execSync(`start \"\" \"${url}\"`);", + " } catch {}", + "}", + "process.stderr.write('Opening browser for alphaXiv login...\\n');", + ].join("\n"); + + const once = patchAlphaHubAuthSource(input); + const twice = patchAlphaHubAuthSource(once); + + assert.equal(twice, once); +}); diff --git a/website/src/content/docs/getting-started/installation.md b/website/src/content/docs/getting-started/installation.md index 1912560..ca0e902 100644 --- a/website/src/content/docs/getting-started/installation.md +++ b/website/src/content/docs/getting-started/installation.md @@ -33,6 +33,29 @@ To update the standalone Feynman app on macOS, Linux, or Windows, rerun the inst `feynman update` is different: it updates installed Pi packages inside Feynman's environment, not the standalone app bundle itself. +## Uninstalling + +Feynman does not currently ship a dedicated `uninstall` command. Remove the standalone launcher and runtime bundle directly, then optionally remove the Feynman home directory if you also want to delete settings, auth, and sessions. + +On macOS or Linux: + +```bash +rm -f ~/.local/bin/feynman +rm -rf ~/.local/share/feynman +# optional: remove settings, auth, sessions, and installed package state +rm -rf ~/.feynman +``` + +On Windows PowerShell: + +```powershell +Remove-Item "$env:LOCALAPPDATA\\Programs\\feynman" -Recurse -Force +# optional: remove settings, auth, sessions, and installed package state +Remove-Item "$HOME\\.feynman" -Recurse -Force +``` + +If you added the launcher directory to `PATH` manually, remove that entry as well. + ## Skills only If you only want Feynman's research skills and not the full terminal runtime, install the skill library separately.