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

@@ -14,7 +14,6 @@ jobs:
outputs: outputs:
version: ${{ steps.version.outputs.version }} version: ${{ steps.version.outputs.version }}
should_publish: ${{ steps.version.outputs.should_publish }} should_publish: ${{ steps.version.outputs.should_publish }}
should_build_release: ${{ steps.version.outputs.should_build_release }}
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v6
- uses: actions/setup-node@v5 - uses: actions/setup-node@v5
@@ -28,46 +27,31 @@ jobs:
echo "version=$LOCAL" >> "$GITHUB_OUTPUT" echo "version=$LOCAL" >> "$GITHUB_OUTPUT"
if [ "$CURRENT" != "$LOCAL" ]; then if [ "$CURRENT" != "$LOCAL" ]; then
echo "should_publish=true" >> "$GITHUB_OUTPUT" echo "should_publish=true" >> "$GITHUB_OUTPUT"
echo "should_build_release=true" >> "$GITHUB_OUTPUT"
elif [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ]; then
echo "should_publish=false" >> "$GITHUB_OUTPUT"
echo "should_build_release=true" >> "$GITHUB_OUTPUT"
else else
echo "should_publish=false" >> "$GITHUB_OUTPUT" echo "should_publish=false" >> "$GITHUB_OUTPUT"
echo "should_build_release=false" >> "$GITHUB_OUTPUT"
fi fi
publish-npm: publish-npm:
needs: version-check needs: version-check
if: needs.version-check.outputs.should_build_release == 'true' if: needs.version-check.outputs.should_publish == 'true'
runs-on: blacksmith-4vcpu-ubuntu-2404 runs-on: blacksmith-4vcpu-ubuntu-2404
permissions: permissions:
contents: read contents: read
steps: steps:
- name: Skip npm publish
if: needs.version-check.outputs.should_publish != 'true'
run: echo "Skipping npm publish; version ${{ needs.version-check.outputs.version }} is already on npm."
- uses: actions/checkout@v6 - uses: actions/checkout@v6
if: needs.version-check.outputs.should_publish == 'true'
- uses: actions/setup-node@v5 - uses: actions/setup-node@v5
if: needs.version-check.outputs.should_publish == 'true'
with: with:
node-version: 24.14.0 node-version: 24.14.0
registry-url: https://registry.npmjs.org registry-url: https://registry.npmjs.org
- if: needs.version-check.outputs.should_publish == 'true' - run: npm ci --ignore-scripts
run: npm ci --ignore-scripts - run: npm run build
- if: needs.version-check.outputs.should_publish == 'true' - run: npm test
run: npm run build
- if: needs.version-check.outputs.should_publish == 'true'
run: npm test
- run: npm publish --access public - run: npm publish --access public
if: needs.version-check.outputs.should_publish == 'true'
env: env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
build-native-bundles: build-native-bundles:
needs: version-check needs: version-check
if: needs.version-check.outputs.should_build_release == 'true'
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -113,12 +97,52 @@ jobs:
name: native-${{ matrix.id }} name: native-${{ matrix.id }}
path: dist/release/* path: dist/release/*
release-edge:
needs:
- version-check
- build-native-bundles
if: needs.build-native-bundles.result == 'success'
runs-on: blacksmith-4vcpu-ubuntu-2404
permissions:
contents: write
steps:
- uses: actions/download-artifact@v4
with:
path: release-assets
merge-multiple: true
- shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ needs.version-check.outputs.version }}
run: |
NOTES="Rolling Feynman bundles from main for the curl/PowerShell installer."
if gh release view edge >/dev/null 2>&1; then
gh release view edge --json assets --jq '.assets[].name' | while IFS= read -r asset; do
[ -n "$asset" ] || continue
gh release delete-asset edge "$asset" --yes
done
gh release upload edge release-assets/*
gh release edit edge \
--title "edge" \
--notes "$NOTES" \
--prerelease \
--draft=false \
--target "$GITHUB_SHA"
else
gh release create edge release-assets/* \
--title "edge" \
--notes "$NOTES" \
--prerelease \
--latest=false \
--target "$GITHUB_SHA"
fi
release-github: release-github:
needs: needs:
- version-check - version-check
- publish-npm - publish-npm
- build-native-bundles - build-native-bundles
if: needs.version-check.outputs.should_build_release == 'true' && needs.build-native-bundles.result == 'success' && needs.publish-npm.result == 'success' if: needs.version-check.outputs.should_publish == 'true' && needs.build-native-bundles.result == 'success' && needs.publish-npm.result == 'success'
runs-on: blacksmith-4vcpu-ubuntu-2404 runs-on: blacksmith-4vcpu-ubuntu-2404
permissions: permissions:
contents: write contents: write
@@ -137,7 +161,8 @@ jobs:
gh release edit "v$VERSION" \ gh release edit "v$VERSION" \
--title "v$VERSION" \ --title "v$VERSION" \
--notes "Standalone Feynman bundles for native installation." \ --notes "Standalone Feynman bundles for native installation." \
--draft=false --draft=false \
--target "$GITHUB_SHA"
else else
gh release create "v$VERSION" release-assets/* \ gh release create "v$VERSION" release-assets/* \
--title "v$VERSION" \ --title "v$VERSION" \

View File

@@ -16,13 +16,16 @@
```bash ```bash
curl -fsSL https://feynman.is/install | bash curl -fsSL https://feynman.is/install | bash
# stable release channel
curl -fsSL https://feynman.is/install | bash -s -- stable
# package manager fallback # package manager fallback
pnpm add -g @companion-ai/feynman pnpm add -g @companion-ai/feynman
bun add -g @companion-ai/feynman bun add -g @companion-ai/feynman
``` ```
Then run `feynman setup` to configure your model and get started. The one-line installer tracks the latest `main` build. Use `stable` or an exact version to pin a release. Then run `feynman setup` to configure your model and get started.
--- ---

View File

@@ -1,22 +1,75 @@
param( param(
[string]$Version = "latest" [string]$Version = "edge"
) )
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
function Resolve-Version { function Normalize-Version {
param([string]$RequestedVersion) param([string]$RequestedVersion)
if ($RequestedVersion -and $RequestedVersion -ne "latest") { if (-not $RequestedVersion) {
return $RequestedVersion.TrimStart("v") return "edge"
} }
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
}
}
if ($normalizedVersion -eq "latest") {
$release = Invoke-RestMethod -Uri "https://api.github.com/repos/getcompanion-ai/feynman/releases/latest" $release = Invoke-RestMethod -Uri "https://api.github.com/repos/getcompanion-ai/feynman/releases/latest"
if (-not $release.tag_name) { if (-not $release.tag_name) {
throw "Failed to resolve the latest Feynman release version." throw "Failed to resolve the latest Feynman release version."
} }
return $release.tag_name.TrimStart("v") $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 { function Get-ArchSuffix {
@@ -28,12 +81,13 @@ function Get-ArchSuffix {
} }
} }
$resolvedVersion = Resolve-Version -RequestedVersion $Version
$archSuffix = Get-ArchSuffix $archSuffix = Get-ArchSuffix
$bundleName = "feynman-$resolvedVersion-win32-$archSuffix" $assetTarget = "win32-$archSuffix"
$archiveName = "$bundleName.zip" $release = Resolve-ReleaseMetadata -RequestedVersion $Version -AssetTarget $assetTarget -BundleExtension "zip"
$baseUrl = if ($env:FEYNMAN_INSTALL_BASE_URL) { $env:FEYNMAN_INSTALL_BASE_URL } else { "https://github.com/getcompanion-ai/feynman/releases/download/v$resolvedVersion" } $resolvedVersion = $release.ResolvedVersion
$downloadUrl = "$baseUrl/$archiveName" $bundleName = $release.BundleName
$archiveName = $release.ArchiveName
$downloadUrl = $release.DownloadUrl
$installRoot = Join-Path $env:LOCALAPPDATA "Programs\feynman" $installRoot = Join-Path $env:LOCALAPPDATA "Programs\feynman"
$installBinDir = Join-Path $installRoot "bin" $installBinDir = Join-Path $installRoot "bin"

View File

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

View File

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

View File

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

View File

@@ -1,22 +1,75 @@
param( param(
[string]$Version = "latest" [string]$Version = "edge"
) )
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
function Resolve-Version { function Normalize-Version {
param([string]$RequestedVersion) param([string]$RequestedVersion)
if ($RequestedVersion -and $RequestedVersion -ne "latest") { if (-not $RequestedVersion) {
return $RequestedVersion.TrimStart("v") return "edge"
} }
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
}
}
if ($normalizedVersion -eq "latest") {
$release = Invoke-RestMethod -Uri "https://api.github.com/repos/getcompanion-ai/feynman/releases/latest" $release = Invoke-RestMethod -Uri "https://api.github.com/repos/getcompanion-ai/feynman/releases/latest"
if (-not $release.tag_name) { if (-not $release.tag_name) {
throw "Failed to resolve the latest Feynman release version." throw "Failed to resolve the latest Feynman release version."
} }
return $release.tag_name.TrimStart("v") $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 { function Get-ArchSuffix {
@@ -28,12 +81,13 @@ function Get-ArchSuffix {
} }
} }
$resolvedVersion = Resolve-Version -RequestedVersion $Version
$archSuffix = Get-ArchSuffix $archSuffix = Get-ArchSuffix
$bundleName = "feynman-$resolvedVersion-win32-$archSuffix" $assetTarget = "win32-$archSuffix"
$archiveName = "$bundleName.zip" $release = Resolve-ReleaseMetadata -RequestedVersion $Version -AssetTarget $assetTarget -BundleExtension "zip"
$baseUrl = if ($env:FEYNMAN_INSTALL_BASE_URL) { $env:FEYNMAN_INSTALL_BASE_URL } else { "https://github.com/getcompanion-ai/feynman/releases/download/v$resolvedVersion" } $resolvedVersion = $release.ResolvedVersion
$downloadUrl = "$baseUrl/$archiveName" $bundleName = $release.BundleName
$archiveName = $release.ArchiveName
$downloadUrl = $release.DownloadUrl
$installRoot = Join-Path $env:LOCALAPPDATA "Programs\feynman" $installRoot = Join-Path $env:LOCALAPPDATA "Programs\feynman"
$installBinDir = Join-Path $installRoot "bin" $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. 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: On **Windows**, open PowerShell as Administrator and run:
```powershell ```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. 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 ## pnpm
If you already have Node.js 20.18.1+ installed, you can install Feynman globally via `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: "/draft", description: "Polished paper-style draft with inline citations from findings" },
{ command: "/autoresearch", description: "Autonomous loop: hypothesize, experiment, measure, repeat" }, { command: "/autoresearch", description: "Autonomous loop: hypothesize, experiment, measure, repeat" },
{ command: "/watch", description: "Recurring monitor for new papers, code, or product updates" }, { 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 = [ const agents = [
@@ -23,11 +24,18 @@ const agents = [
] ]
const sources = [ 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: "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" }, { 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 = [ const terminalCommands = [
{ command: 'feynman "what do we know about scaling laws"', description: "Cited research brief from papers and web" }, { 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" }, { command: 'feynman deepresearch "mechanistic interpretability"', description: "Multi-agent deep dive with synthesis and verification" },
@@ -163,10 +171,10 @@ const installCommands = [
<section class="py-16"> <section class="py-16">
<div class="flex flex-col items-center gap-8 text-center"> <div class="flex flex-col items-center gap-8 text-center">
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
<h2 class="text-2xl font-bold tracking-tight sm:text-3xl">Sources</h2> <h2 class="text-2xl font-bold tracking-tight sm:text-3xl">Skills &amp; Tools</h2>
<p class="text-muted-foreground">Where Feynman finds information.</p> <p class="text-muted-foreground">How Feynman searches, remembers, and exports work.</p>
</div> </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) => ( {sources.map((source) => (
<Card client:load size="sm" className="text-center"> <Card client:load size="sm" className="text-center">
<CardHeader client:load className="items-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 items-center gap-8 text-center">
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
<h2 class="text-2xl font-bold tracking-tight sm:text-3xl">Compute</h2> <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>
<Card client:load size="sm" className="w-full max-w-md text-center"> <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"> <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> <CardTitle client:load>
<CardDescription client:load>Isolated container execution for safe local experiments</CardDescription> <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> </CardHeader>
</Card> </Card>
))}
</div>
</div> </div>
</section> </section>
<section class="flex flex-col items-center gap-6 py-20 text-center"> <section class="flex flex-col items-center gap-6 py-20 text-center">
<p class="text-muted-foreground"> <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> </p>
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<a href="/docs/getting-started/installation"> <a href="/docs/getting-started/installation">