Update edge installer and release flow

This commit is contained in:
Advait Paliwal
2026-03-25 01:06:11 -07:00
parent 8178173ff7
commit 4ac668c50a
9 changed files with 332 additions and 94 deletions

View File

@@ -5,7 +5,7 @@
"private": true,
"scripts": {
"dev": "astro dev",
"build": "astro build",
"build": "node ../scripts/sync-website-installers.mjs && astro build",
"preview": "astro preview",
"astro": "astro",
"lint": "eslint .",

View File

@@ -2,7 +2,7 @@
set -eu
VERSION="${1:-latest}"
VERSION="${1:-edge}"
INSTALL_BIN_DIR="${FEYNMAN_INSTALL_BIN_DIR:-$HOME/.local/bin}"
INSTALL_APP_DIR="${FEYNMAN_INSTALL_APP_DIR:-$HOME/.local/share/feynman}"
SKIP_PATH_UPDATE="${FEYNMAN_INSTALL_SKIP_PATH_UPDATE:-0}"
@@ -54,7 +54,10 @@ run_with_spinner() {
normalize_version() {
case "$1" in
"" | latest)
"" | edge)
printf 'edge\n'
;;
latest | stable)
printf 'latest\n'
;;
v*)
@@ -157,23 +160,53 @@ require_command() {
fi
}
resolve_version() {
resolve_release_metadata() {
normalized_version="$(normalize_version "$VERSION")"
if [ "$normalized_version" != "latest" ]; then
printf '%s\n' "$normalized_version"
if [ "$normalized_version" = "edge" ]; then
release_json="$(download_text "https://api.github.com/repos/getcompanion-ai/feynman/releases/tags/edge")"
asset_url=""
for candidate in $(printf '%s\n' "$release_json" | sed -n 's/.*"browser_download_url":[[:space:]]*"\([^"]*\)".*/\1/p'); do
case "$candidate" in
*/feynman-*-${asset_target}.${archive_extension})
asset_url="$candidate"
break
;;
esac
done
if [ -z "$asset_url" ]; then
echo "Failed to resolve the latest Feynman edge bundle." >&2
exit 1
fi
archive_name="${asset_url##*/}"
bundle_name="${archive_name%.$archive_extension}"
resolved_version="${bundle_name#feynman-}"
resolved_version="${resolved_version%-${asset_target}}"
printf '%s\n%s\n%s\n%s\n' "$resolved_version" "$bundle_name" "$archive_name" "$asset_url"
return
fi
release_json="$(download_text "https://api.github.com/repos/getcompanion-ai/feynman/releases/latest")"
resolved="$(printf '%s\n' "$release_json" | sed -n 's/.*"tag_name":[[:space:]]*"v\([^"]*\)".*/\1/p' | head -n 1)"
if [ "$normalized_version" = "latest" ]; then
release_json="$(download_text "https://api.github.com/repos/getcompanion-ai/feynman/releases/latest")"
resolved_version="$(printf '%s\n' "$release_json" | sed -n 's/.*"tag_name":[[:space:]]*"v\([^"]*\)".*/\1/p' | head -n 1)"
if [ -z "$resolved" ]; then
echo "Failed to resolve the latest Feynman release version." >&2
exit 1
if [ -z "$resolved_version" ]; then
echo "Failed to resolve the latest Feynman release version." >&2
exit 1
fi
else
resolved_version="$normalized_version"
fi
printf '%s\n' "$resolved"
bundle_name="feynman-${resolved_version}-${asset_target}"
archive_name="${bundle_name}.${archive_extension}"
download_url="${FEYNMAN_INSTALL_BASE_URL:-https://github.com/getcompanion-ai/feynman/releases/download/v${resolved_version}}/${archive_name}"
printf '%s\n%s\n%s\n%s\n' "$resolved_version" "$bundle_name" "$archive_name" "$download_url"
}
case "$(uname -s)" in
@@ -205,12 +238,13 @@ esac
require_command mktemp
require_command tar
resolved_version="$(resolve_version)"
asset_target="$os-$arch"
bundle_name="feynman-${resolved_version}-${asset_target}"
archive_name="${bundle_name}.tar.gz"
base_url="${FEYNMAN_INSTALL_BASE_URL:-https://github.com/getcompanion-ai/feynman/releases/download/v${resolved_version}}"
download_url="${base_url}/${archive_name}"
archive_extension="tar.gz"
release_metadata="$(resolve_release_metadata)"
resolved_version="$(printf '%s\n' "$release_metadata" | sed -n '1p')"
bundle_name="$(printf '%s\n' "$release_metadata" | sed -n '2p')"
archive_name="$(printf '%s\n' "$release_metadata" | sed -n '3p')"
download_url="$(printf '%s\n' "$release_metadata" | sed -n '4p')"
step "Installing Feynman ${resolved_version} for ${asset_target}"

View File

@@ -1,22 +1,75 @@
param(
[string]$Version = "latest"
[string]$Version = "edge"
)
$ErrorActionPreference = "Stop"
function Resolve-Version {
function Normalize-Version {
param([string]$RequestedVersion)
if ($RequestedVersion -and $RequestedVersion -ne "latest") {
return $RequestedVersion.TrimStart("v")
if (-not $RequestedVersion) {
return "edge"
}
$release = Invoke-RestMethod -Uri "https://api.github.com/repos/getcompanion-ai/feynman/releases/latest"
if (-not $release.tag_name) {
throw "Failed to resolve the latest Feynman release version."
switch ($RequestedVersion.ToLowerInvariant()) {
"edge" { return "edge" }
"latest" { return "latest" }
"stable" { return "latest" }
default { return $RequestedVersion.TrimStart("v") }
}
}
function Resolve-ReleaseMetadata {
param(
[string]$RequestedVersion,
[string]$AssetTarget,
[string]$BundleExtension
)
$normalizedVersion = Normalize-Version -RequestedVersion $RequestedVersion
if ($normalizedVersion -eq "edge") {
$release = Invoke-RestMethod -Uri "https://api.github.com/repos/getcompanion-ai/feynman/releases/tags/edge"
$asset = $release.assets | Where-Object { $_.name -like "feynman-*-$AssetTarget.$BundleExtension" } | Select-Object -First 1
if (-not $asset) {
throw "Failed to resolve the latest Feynman edge bundle."
}
$archiveName = $asset.name
$suffix = ".$BundleExtension"
$bundleName = $archiveName.Substring(0, $archiveName.Length - $suffix.Length)
$resolvedVersion = $bundleName.Substring("feynman-".Length)
$resolvedVersion = $resolvedVersion.Substring(0, $resolvedVersion.Length - ("-$AssetTarget").Length)
return [PSCustomObject]@{
ResolvedVersion = $resolvedVersion
BundleName = $bundleName
ArchiveName = $archiveName
DownloadUrl = $asset.browser_download_url
}
}
return $release.tag_name.TrimStart("v")
if ($normalizedVersion -eq "latest") {
$release = Invoke-RestMethod -Uri "https://api.github.com/repos/getcompanion-ai/feynman/releases/latest"
if (-not $release.tag_name) {
throw "Failed to resolve the latest Feynman release version."
}
$resolvedVersion = $release.tag_name.TrimStart("v")
} else {
$resolvedVersion = $normalizedVersion
}
$bundleName = "feynman-$resolvedVersion-$AssetTarget"
$archiveName = "$bundleName.$BundleExtension"
$baseUrl = if ($env:FEYNMAN_INSTALL_BASE_URL) { $env:FEYNMAN_INSTALL_BASE_URL } else { "https://github.com/getcompanion-ai/feynman/releases/download/v$resolvedVersion" }
return [PSCustomObject]@{
ResolvedVersion = $resolvedVersion
BundleName = $bundleName
ArchiveName = $archiveName
DownloadUrl = "$baseUrl/$archiveName"
}
}
function Get-ArchSuffix {
@@ -28,12 +81,13 @@ function Get-ArchSuffix {
}
}
$resolvedVersion = Resolve-Version -RequestedVersion $Version
$archSuffix = Get-ArchSuffix
$bundleName = "feynman-$resolvedVersion-win32-$archSuffix"
$archiveName = "$bundleName.zip"
$baseUrl = if ($env:FEYNMAN_INSTALL_BASE_URL) { $env:FEYNMAN_INSTALL_BASE_URL } else { "https://github.com/getcompanion-ai/feynman/releases/download/v$resolvedVersion" }
$downloadUrl = "$baseUrl/$archiveName"
$assetTarget = "win32-$archSuffix"
$release = Resolve-ReleaseMetadata -RequestedVersion $Version -AssetTarget $assetTarget -BundleExtension "zip"
$resolvedVersion = $release.ResolvedVersion
$bundleName = $release.BundleName
$archiveName = $release.ArchiveName
$downloadUrl = $release.DownloadUrl
$installRoot = Join-Path $env:LOCALAPPDATA "Programs\feynman"
$installBinDir = Join-Path $installRoot "bin"

View File

@@ -17,6 +17,8 @@ curl -fsSL https://feynman.is/install | bash
The installer detects your OS and architecture automatically. On macOS it supports both Intel and Apple Silicon. On Linux it supports x64 and arm64. The launcher is installed to `~/.local/bin`, the bundled runtime is unpacked into `~/.local/share/feynman`, and your `PATH` is updated when needed.
By default, the one-line installer tracks the rolling `edge` channel from `main`.
On **Windows**, open PowerShell as Administrator and run:
```powershell
@@ -25,6 +27,22 @@ irm https://feynman.is/install.ps1 | iex
This installs the Windows runtime bundle under `%LOCALAPPDATA%\Programs\feynman`, adds its launcher to your user `PATH`, and lets you re-run the installer at any time to update.
## Stable or pinned releases
If you want the latest tagged release instead of the rolling `edge` channel:
```bash
curl -fsSL https://feynman.is/install | bash -s -- stable
```
On Windows:
```powershell
& ([scriptblock]::Create((irm https://feynman.is/install.ps1))) -Version stable
```
You can also pin an exact version by replacing `stable` with a version such as `0.2.13`.
## pnpm
If you already have Node.js 20.18.1+ installed, you can install Feynman globally via `pnpm`:

View File

@@ -13,6 +13,7 @@ const workflows = [
{ command: "/draft", description: "Polished paper-style draft with inline citations from findings" },
{ command: "/autoresearch", description: "Autonomous loop: hypothesize, experiment, measure, repeat" },
{ command: "/watch", description: "Recurring monitor for new papers, code, or product updates" },
{ command: "/outputs", description: "Browse all research artifacts, papers, notes, and experiments" },
]
const agents = [
@@ -23,11 +24,18 @@ const agents = [
]
const sources = [
{ name: "AlphaXiv", description: "Paper search, Q&A, code reading, and persistent annotations", href: "https://alphaxiv.org" },
{ name: "AlphaXiv", description: "Paper search, Q&A, code reading, and annotations via the alpha CLI", href: "https://alphaxiv.org" },
{ name: "Web search", description: "Searches via Gemini or Perplexity" },
{ name: "Session search", description: "Indexed recall across prior research sessions" },
{ name: "Preview", description: "Browser and PDF export of generated artifacts" },
]
const compute = [
{ name: "Docker", description: "Isolated local containers for safe experiments", href: "https://www.docker.com/" },
{ name: "Modal", description: "Serverless GPU compute for burst training and inference", href: "https://modal.com/" },
{ name: "RunPod", description: "Persistent GPU pods with SSH access for long-running runs", href: "https://www.runpod.io/" },
]
const terminalCommands = [
{ command: 'feynman "what do we know about scaling laws"', description: "Cited research brief from papers and web" },
{ command: 'feynman deepresearch "mechanistic interpretability"', description: "Multi-agent deep dive with synthesis and verification" },
@@ -163,10 +171,10 @@ const installCommands = [
<section class="py-16">
<div class="flex flex-col items-center gap-8 text-center">
<div class="flex flex-col gap-2">
<h2 class="text-2xl font-bold tracking-tight sm:text-3xl">Sources</h2>
<p class="text-muted-foreground">Where Feynman finds information.</p>
<h2 class="text-2xl font-bold tracking-tight sm:text-3xl">Skills &amp; Tools</h2>
<p class="text-muted-foreground">How Feynman searches, remembers, and exports work.</p>
</div>
<div class="grid w-full gap-4 sm:grid-cols-3">
<div class="grid w-full gap-4 sm:grid-cols-2 lg:grid-cols-4">
{sources.map((source) => (
<Card client:load size="sm" className="text-center">
<CardHeader client:load className="items-center">
@@ -191,20 +199,28 @@ const installCommands = [
<div class="flex flex-col items-center gap-8 text-center">
<div class="flex flex-col gap-2">
<h2 class="text-2xl font-bold tracking-tight sm:text-3xl">Compute</h2>
<p class="text-muted-foreground">Experiments run in sandboxed Docker containers. Your code stays local.</p>
<p class="text-muted-foreground">Run experiments locally or burst onto managed GPU infrastructure when needed.</p>
</div>
<div class="grid w-full gap-4 sm:grid-cols-3">
{compute.map((provider) => (
<Card client:load size="sm" className="text-center">
<CardHeader client:load className="items-center">
<CardTitle client:load>
<a href={provider.href} target="_blank" rel="noopener noreferrer" class="text-primary hover:underline">
{provider.name}
</a>
</CardTitle>
<CardDescription client:load>{provider.description}</CardDescription>
</CardHeader>
</Card>
))}
</div>
<Card client:load size="sm" className="w-full max-w-md text-center">
<CardHeader client:load className="items-center">
<CardTitle client:load><a href="https://www.docker.com/" target="_blank" rel="noopener noreferrer" class="text-primary hover:underline">Docker</a></CardTitle>
<CardDescription client:load>Isolated container execution for safe local experiments</CardDescription>
</CardHeader>
</Card>
</div>
</section>
<section class="flex flex-col items-center gap-6 py-20 text-center">
<p class="text-muted-foreground">
Built on <a href="https://github.com/badlogic/pi-mono" class="text-primary hover:underline">Pi</a> and <a href="https://www.alphaxiv.org/" class="text-primary hover:underline">alphaXiv</a>. MIT licensed.
Built on <a href="https://github.com/badlogic/pi-mono" class="text-primary hover:underline">Pi</a> and <a href="https://www.alphaxiv.org/" class="text-primary hover:underline">alphaXiv</a>. Capabilities ship as Pi skills and every output stays source-grounded.
</p>
<div class="flex items-center gap-3">
<a href="/docs/getting-started/installation">