fix: improve WSL login fallback
This commit is contained in:
@@ -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.
|
- 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.
|
- 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)
|
### 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.
|
- Objective: Verify citations in the capital-of-France draft and produce a cited verifier brief.
|
||||||
|
|||||||
@@ -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 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`.
|
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
|
### Skills Only
|
||||||
|
|||||||
1
scripts/lib/alpha-hub-auth-patch.d.mts
Normal file
1
scripts/lib/alpha-hub-auth-patch.d.mts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export declare function patchAlphaHubAuthSource(source: string): string;
|
||||||
66
scripts/lib/alpha-hub-auth-patch.mjs
Normal file
66
scripts/lib/alpha-hub-auth-patch.mjs
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
const LEGACY_SUCCESS_HTML = "'<html><body><h2>Logged in to Alpha Hub</h2><p>You can close this tab.</p></body></html>'";
|
||||||
|
const LEGACY_ERROR_HTML = "'<html><body><h2>Login failed</h2><p>You can close this tab.</p></body></html>'";
|
||||||
|
|
||||||
|
const bodyAttr = 'style="font-family:system-ui,sans-serif;text-align:center;padding-top:20vh;background:#050a08;color:#f0f5f2"';
|
||||||
|
const logo = '<h1 style="font-family:monospace;font-size:48px;color:#34d399;margin:0">feynman</h1>';
|
||||||
|
|
||||||
|
const FEYNMAN_SUCCESS_HTML = `'<html><body ${bodyAttr}>${logo}<h2 style="color:#34d399;margin-top:16px">Logged in</h2><p style="color:#8aaa9a">You can close this tab.</p></body></html>'`;
|
||||||
|
const FEYNMAN_ERROR_HTML = `'<html><body ${bodyAttr}>${logo}<h2 style="color:#ef4444;margin-top:16px">Login failed</h2><p style="color:#8aaa9a">You can close this tab.</p></body></html>'`;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import { homedir } from "node:os";
|
|||||||
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";
|
||||||
|
import { patchAlphaHubAuthSource } from "./lib/alpha-hub-auth-patch.mjs";
|
||||||
import { patchPiExtensionLoaderSource } from "./lib/pi-extension-loader-patch.mjs";
|
import { patchPiExtensionLoaderSource } from "./lib/pi-extension-loader-patch.mjs";
|
||||||
import { patchPiGoogleLegacySchemaSource } from "./lib/pi-google-legacy-schema-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";
|
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;
|
: null;
|
||||||
|
|
||||||
if (alphaHubAuthPath && existsSync(alphaHubAuthPath)) {
|
if (alphaHubAuthPath && existsSync(alphaHubAuthPath)) {
|
||||||
let source = readFileSync(alphaHubAuthPath, "utf8");
|
const source = readFileSync(alphaHubAuthPath, "utf8");
|
||||||
const oldSuccess = "'<html><body><h2>Logged in to Alpha Hub</h2><p>You can close this tab.</p></body></html>'";
|
const patched = patchAlphaHubAuthSource(source);
|
||||||
const oldError = "'<html><body><h2>Login failed</h2><p>You can close this tab.</p></body></html>'";
|
if (patched !== source) {
|
||||||
const bodyAttr = `style="font-family:system-ui,sans-serif;text-align:center;padding-top:20vh;background:#050a08;color:#f0f5f2"`;
|
writeFileSync(alphaHubAuthPath, patched, "utf8");
|
||||||
const logo = `<h1 style="font-family:monospace;font-size:48px;color:#34d399;margin:0">feynman</h1>`;
|
|
||||||
const newSuccess = `'<html><body ${bodyAttr}>${logo}<h2 style="color:#34d399;margin-top:16px">Logged in</h2><p style="color:#8aaa9a">You can close this tab.</p></body></html>'`;
|
|
||||||
const newError = `'<html><body ${bodyAttr}>${logo}<h2 style="color:#ef4444;margin-top:16px">Login failed</h2><p style="color:#8aaa9a">You can close this tab.</p></body></html>'`;
|
|
||||||
if (source.includes(oldSuccess)) {
|
|
||||||
source = source.replace(oldSuccess, newSuccess);
|
|
||||||
}
|
}
|
||||||
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)) {
|
if (existsSync(piMemoryPath)) {
|
||||||
|
|||||||
51
tests/alpha-hub-auth-patch.test.ts
Normal file
51
tests/alpha-hub-auth-patch.test.ts
Normal file
@@ -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);
|
||||||
|
});
|
||||||
@@ -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.
|
`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
|
## Skills only
|
||||||
|
|
||||||
If you only want Feynman's research skills and not the full terminal runtime, install the skill library separately.
|
If you only want Feynman's research skills and not the full terminal runtime, install the skill library separately.
|
||||||
|
|||||||
Reference in New Issue
Block a user