Add skills-only installers
This commit is contained in:
205
website/public/install-skills
Normal file
205
website/public/install-skills
Normal file
@@ -0,0 +1,205 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
VERSION="edge"
|
||||
SCOPE="${FEYNMAN_SKILLS_SCOPE:-user}"
|
||||
TARGET_DIR="${FEYNMAN_SKILLS_DIR:-}"
|
||||
|
||||
step() {
|
||||
printf '==> %s\n' "$1"
|
||||
}
|
||||
|
||||
normalize_version() {
|
||||
case "$1" in
|
||||
"" | edge)
|
||||
printf 'edge\n'
|
||||
;;
|
||||
latest | stable)
|
||||
printf 'latest\n'
|
||||
;;
|
||||
v*)
|
||||
printf '%s\n' "${1#v}"
|
||||
;;
|
||||
*)
|
||||
printf '%s\n' "$1"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
download_file() {
|
||||
url="$1"
|
||||
output="$2"
|
||||
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
if [ -t 2 ]; then
|
||||
curl -fL --progress-bar "$url" -o "$output"
|
||||
else
|
||||
curl -fsSL "$url" -o "$output"
|
||||
fi
|
||||
return
|
||||
fi
|
||||
|
||||
if command -v wget >/dev/null 2>&1; then
|
||||
if [ -t 2 ]; then
|
||||
wget --show-progress -O "$output" "$url"
|
||||
else
|
||||
wget -q -O "$output" "$url"
|
||||
fi
|
||||
return
|
||||
fi
|
||||
|
||||
echo "curl or wget is required to install Feynman skills." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
download_text() {
|
||||
url="$1"
|
||||
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fsSL "$url"
|
||||
return
|
||||
fi
|
||||
|
||||
if command -v wget >/dev/null 2>&1; then
|
||||
wget -q -O - "$url"
|
||||
return
|
||||
fi
|
||||
|
||||
echo "curl or wget is required to install Feynman skills." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
resolve_version() {
|
||||
normalized_version="$(normalize_version "$VERSION")"
|
||||
|
||||
if [ "$normalized_version" = "edge" ]; then
|
||||
printf 'edge\nmain\n'
|
||||
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
|
||||
|
||||
printf '%s\nv%s\n' "$resolved_version" "$resolved_version"
|
||||
return
|
||||
fi
|
||||
|
||||
printf '%s\nv%s\n' "$normalized_version" "$normalized_version"
|
||||
}
|
||||
|
||||
resolve_target_dir() {
|
||||
if [ -n "$TARGET_DIR" ]; then
|
||||
printf '%s\n' "$TARGET_DIR"
|
||||
return
|
||||
fi
|
||||
|
||||
case "$SCOPE" in
|
||||
repo)
|
||||
printf '%s/.agents/skills/feynman\n' "$PWD"
|
||||
;;
|
||||
user)
|
||||
codex_home="${CODEX_HOME:-$HOME/.codex}"
|
||||
printf '%s/skills/feynman\n' "$codex_home"
|
||||
;;
|
||||
*)
|
||||
echo "Unknown scope: $SCOPE (expected --user or --repo)" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--repo)
|
||||
SCOPE="repo"
|
||||
;;
|
||||
--user)
|
||||
SCOPE="user"
|
||||
;;
|
||||
--dir)
|
||||
if [ $# -lt 2 ]; then
|
||||
echo "Usage: install-skills.sh [edge|stable|latest|<version>] [--user|--repo] [--dir <path>]" >&2
|
||||
exit 1
|
||||
fi
|
||||
TARGET_DIR="$2"
|
||||
shift
|
||||
;;
|
||||
edge|stable|latest|v*|[0-9]*)
|
||||
VERSION="$1"
|
||||
;;
|
||||
*)
|
||||
echo "Unknown argument: $1" >&2
|
||||
echo "Usage: install-skills.sh [edge|stable|latest|<version>] [--user|--repo] [--dir <path>]" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
archive_metadata="$(resolve_version)"
|
||||
resolved_version="$(printf '%s\n' "$archive_metadata" | sed -n '1p')"
|
||||
git_ref="$(printf '%s\n' "$archive_metadata" | sed -n '2p')"
|
||||
|
||||
archive_url=""
|
||||
case "$git_ref" in
|
||||
main)
|
||||
archive_url="https://github.com/getcompanion-ai/feynman/archive/refs/heads/main.tar.gz"
|
||||
;;
|
||||
v*)
|
||||
archive_url="https://github.com/getcompanion-ai/feynman/archive/refs/tags/${git_ref}.tar.gz"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "$archive_url" ]; then
|
||||
echo "Could not resolve a download URL for ref: $git_ref" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
install_dir="$(resolve_target_dir)"
|
||||
|
||||
step "Installing Feynman skills ${resolved_version} (${SCOPE})"
|
||||
|
||||
tmp_dir="$(mktemp -d)"
|
||||
cleanup() {
|
||||
rm -rf "$tmp_dir"
|
||||
}
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
archive_path="$tmp_dir/feynman-skills.tar.gz"
|
||||
step "Downloading skills archive"
|
||||
download_file "$archive_url" "$archive_path"
|
||||
|
||||
extract_dir="$tmp_dir/extract"
|
||||
mkdir -p "$extract_dir"
|
||||
step "Extracting skills"
|
||||
tar -xzf "$archive_path" -C "$extract_dir"
|
||||
|
||||
source_root="$(find "$extract_dir" -mindepth 1 -maxdepth 1 -type d | head -n 1)"
|
||||
if [ -z "$source_root" ] || [ ! -d "$source_root/skills" ]; then
|
||||
echo "Could not find skills/ in downloaded archive." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$(dirname "$install_dir")"
|
||||
rm -rf "$install_dir"
|
||||
mkdir -p "$install_dir"
|
||||
cp -R "$source_root/skills/." "$install_dir/"
|
||||
|
||||
step "Installed skills to $install_dir"
|
||||
case "$SCOPE" in
|
||||
repo)
|
||||
step "Repo-local skills will be discovered automatically from .agents/skills"
|
||||
;;
|
||||
user)
|
||||
step "User-level skills will be discovered from \$CODEX_HOME/skills"
|
||||
;;
|
||||
esac
|
||||
|
||||
printf 'Feynman skills %s installed successfully.\n' "$resolved_version"
|
||||
126
website/public/install-skills.ps1
Normal file
126
website/public/install-skills.ps1
Normal file
@@ -0,0 +1,126 @@
|
||||
param(
|
||||
[string]$Version = "edge",
|
||||
[ValidateSet("User", "Repo")]
|
||||
[string]$Scope = "User",
|
||||
[string]$TargetDir = ""
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
function Normalize-Version {
|
||||
param([string]$RequestedVersion)
|
||||
|
||||
if (-not $RequestedVersion) {
|
||||
return "edge"
|
||||
}
|
||||
|
||||
switch ($RequestedVersion.ToLowerInvariant()) {
|
||||
"edge" { return "edge" }
|
||||
"latest" { return "latest" }
|
||||
"stable" { return "latest" }
|
||||
default { return $RequestedVersion.TrimStart("v") }
|
||||
}
|
||||
}
|
||||
|
||||
function Resolve-VersionMetadata {
|
||||
param([string]$RequestedVersion)
|
||||
|
||||
$normalizedVersion = Normalize-Version -RequestedVersion $RequestedVersion
|
||||
|
||||
if ($normalizedVersion -eq "edge") {
|
||||
return [PSCustomObject]@{
|
||||
ResolvedVersion = "edge"
|
||||
GitRef = "main"
|
||||
DownloadUrl = "https://github.com/getcompanion-ai/feynman/archive/refs/heads/main.zip"
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
return [PSCustomObject]@{
|
||||
ResolvedVersion = $resolvedVersion
|
||||
GitRef = "v$resolvedVersion"
|
||||
DownloadUrl = "https://github.com/getcompanion-ai/feynman/archive/refs/tags/v$resolvedVersion.zip"
|
||||
}
|
||||
}
|
||||
|
||||
function Resolve-InstallDir {
|
||||
param(
|
||||
[string]$ResolvedScope,
|
||||
[string]$ResolvedTargetDir
|
||||
)
|
||||
|
||||
if ($ResolvedTargetDir) {
|
||||
return $ResolvedTargetDir
|
||||
}
|
||||
|
||||
if ($ResolvedScope -eq "Repo") {
|
||||
return Join-Path (Get-Location) ".agents\skills\feynman"
|
||||
}
|
||||
|
||||
$codexHome = if ($env:CODEX_HOME) { $env:CODEX_HOME } else { Join-Path $HOME ".codex" }
|
||||
return Join-Path $codexHome "skills\feynman"
|
||||
}
|
||||
|
||||
$metadata = Resolve-VersionMetadata -RequestedVersion $Version
|
||||
$resolvedVersion = $metadata.ResolvedVersion
|
||||
$downloadUrl = $metadata.DownloadUrl
|
||||
$installDir = Resolve-InstallDir -ResolvedScope $Scope -ResolvedTargetDir $TargetDir
|
||||
|
||||
$tmpDir = Join-Path ([System.IO.Path]::GetTempPath()) ("feynman-skills-install-" + [System.Guid]::NewGuid().ToString("N"))
|
||||
New-Item -ItemType Directory -Path $tmpDir | Out-Null
|
||||
|
||||
try {
|
||||
$archivePath = Join-Path $tmpDir "feynman-skills.zip"
|
||||
$extractDir = Join-Path $tmpDir "extract"
|
||||
|
||||
Write-Host "==> Downloading Feynman skills $resolvedVersion"
|
||||
Invoke-WebRequest -Uri $downloadUrl -OutFile $archivePath
|
||||
|
||||
Write-Host "==> Extracting skills"
|
||||
Expand-Archive -LiteralPath $archivePath -DestinationPath $extractDir -Force
|
||||
|
||||
$sourceRoot = Get-ChildItem -Path $extractDir -Directory | Select-Object -First 1
|
||||
if (-not $sourceRoot) {
|
||||
throw "Could not find extracted Feynman archive."
|
||||
}
|
||||
|
||||
$skillsSource = Join-Path $sourceRoot.FullName "skills"
|
||||
if (-not (Test-Path $skillsSource)) {
|
||||
throw "Could not find skills/ in downloaded archive."
|
||||
}
|
||||
|
||||
$installParent = Split-Path $installDir -Parent
|
||||
if ($installParent) {
|
||||
New-Item -ItemType Directory -Path $installParent -Force | Out-Null
|
||||
}
|
||||
|
||||
if (Test-Path $installDir) {
|
||||
Remove-Item -Recurse -Force $installDir
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Path $installDir -Force | Out-Null
|
||||
Copy-Item -Path (Join-Path $skillsSource "*") -Destination $installDir -Recurse -Force
|
||||
|
||||
Write-Host "==> Installed skills to $installDir"
|
||||
if ($Scope -eq "Repo") {
|
||||
Write-Host "Repo-local skills will be discovered automatically from .agents/skills."
|
||||
} else {
|
||||
Write-Host "User-level skills will be discovered from `$CODEX_HOME/skills."
|
||||
}
|
||||
|
||||
Write-Host "Feynman skills $resolvedVersion installed successfully."
|
||||
} finally {
|
||||
if (Test-Path $tmpDir) {
|
||||
Remove-Item -Recurse -Force $tmpDir
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,36 @@ 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.
|
||||
|
||||
## Skills only
|
||||
|
||||
If you only want Feynman's research skills and not the full terminal runtime, install the skill library separately.
|
||||
|
||||
For a user-level install into `~/.codex/skills/feynman`:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://feynman.is/install-skills | bash
|
||||
```
|
||||
|
||||
For a repo-local install into `.agents/skills/feynman` under the current repository:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://feynman.is/install-skills | bash -s -- --repo
|
||||
```
|
||||
|
||||
On Windows, install the skills into your Codex skill directory:
|
||||
|
||||
```powershell
|
||||
irm https://feynman.is/install-skills.ps1 | iex
|
||||
```
|
||||
|
||||
Or install them repo-locally:
|
||||
|
||||
```powershell
|
||||
& ([scriptblock]::Create((irm https://feynman.is/install-skills.ps1))) -Scope Repo
|
||||
```
|
||||
|
||||
These installers download only the `skills/` tree from the Feynman repository. They do not install the Feynman terminal, bundled Node runtime, auth storage, or Pi packages.
|
||||
|
||||
## Stable or pinned releases
|
||||
|
||||
If you want the latest tagged release instead of the rolling `edge` channel:
|
||||
|
||||
@@ -103,6 +103,10 @@ const installCommands = [
|
||||
GitHub
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Need just the skills? <a href="/docs/getting-started/installation" class="text-primary hover:underline">Install the skills-only bundle</a>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<img src="/hero.png" class="w-full" alt="Feynman CLI" />
|
||||
|
||||
Reference in New Issue
Block a user