Update edge installer and release flow
This commit is contained in:
69
.github/workflows/publish.yml
vendored
69
.github/workflows/publish.yml
vendored
@@ -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" \
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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}"
|
||||||
|
|
||||||
|
|||||||
@@ -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 .",
|
||||||
|
|||||||
@@ -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}"
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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`:
|
||||||
|
|||||||
@@ -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 & 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">
|
||||||
|
|||||||
Reference in New Issue
Block a user