mirror of
https://github.com/OpenRouterTeam/spawn.git
synced 2026-07-09 17:18:34 +00:00
chore: rename moved repos (OpenRouterTeam→OpenRouterLabs, sst→anomalyco) (#3445)
* chore: rename moved repos OpenRouterTeam→OpenRouterLabs and sst/opencode→anomalyco
Pure mechanical find/replace across the tree — both repos were renamed on
GitHub and only resolved via 301 redirects (fragile; hijack risk if the old
names are re-registered).
- OpenRouterTeam/spawn → OpenRouterLabs/spawn (141 refs): hardcoded REPO
consts (manifest.ts, agent-tarball.ts), release-download URLs in every
sh/{cloud}/{agent}.sh, gh/raw/asset URLs, docs, tests, fixtures.
- sst/opencode → anomalyco/opencode (5 refs): manifest, README, agent-setup.ts
download cmd, opencode.Dockerfile.
No behavior change. biome clean (205 files). CLI version 1.1.0 → 1.1.1.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(spawn): deflake cmdRun + hetzner tests (disable telemetry in tests, route hetzner mock by endpoint)
* test(spawn): deflake cmdRun + hetzner tests (disable telemetry in tests, route hetzner mock by endpoint)
* test(spawn): deflake cmdRun + hetzner tests (disable telemetry in tests, route hetzner mock by endpoint)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: spa-the-spawn-maintainer[bot] <286559366+spa-the-spawn-maintainer[bot]@users.noreply.github.com>
This commit is contained in:
parent
c21a65b777
commit
4b62e8735f
115 changed files with 263 additions and 197 deletions
|
|
@ -68,7 +68,7 @@ To add: same steps as before (manifest.json entry, matrix entries, implement on
|
|||
|
||||
## 4. Respond to GitHub issues
|
||||
|
||||
Check `gh issue list --repo OpenRouterTeam/spawn --state open` for user requests:
|
||||
Check `gh issue list --repo OpenRouterLabs/spawn --state open` for user requests:
|
||||
- If someone requests an agent or cloud, implement it and comment with the PR link
|
||||
- If something is already implemented, close the issue with a note
|
||||
- If a bug is reported, fix it
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ Before editing ANY files:
|
|||
```
|
||||
5. **Open a draft PR, then merge when done:**
|
||||
```bash
|
||||
gh pr create --draft --repo OpenRouterTeam/spawn
|
||||
gh pr create --draft --repo OpenRouterLabs/spawn
|
||||
gh pr ready NUMBER && gh pr merge --squash NUMBER
|
||||
```
|
||||
6. **Clean up** the worktree:
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ macOS ships bash 3.2. All scripts MUST work on it:
|
|||
- `#!/bin/bash` + `set -eo pipefail` (no `u` flag)
|
||||
- Use `${VAR:-}` for all optional env var checks (`OPENROUTER_API_KEY`, cloud tokens, etc.)
|
||||
- Primary script URL: `https://openrouter.ai/labs/spawn/{path}` (CDN proxy, maps to repo `sh/`, e.g., `{cloud}/{agent}.sh`)
|
||||
- Fallback script URL: `https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/sh/{path}`
|
||||
- Version check URL: `https://github.com/OpenRouterTeam/spawn/releases/download/cli-latest/version` (GitHub release artifact)
|
||||
- Fallback script URL: `https://raw.githubusercontent.com/OpenRouterLabs/spawn/main/sh/{path}`
|
||||
- Version check URL: `https://github.com/OpenRouterLabs/spawn/releases/download/cli-latest/version` (GitHub release artifact)
|
||||
- All env vars documented in the cloud's `sh/{cloud}/README.md`
|
||||
|
||||
## Use Bun + TypeScript for Inline Scripting — NEVER python/python3
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ set -eo pipefail
|
|||
|
||||
_COLLAB_CACHE_FILE="/tmp/spawn-collaborators-cache"
|
||||
_COLLAB_CACHE_TTL=600 # 10 minutes
|
||||
_COLLAB_REPO="OpenRouterTeam/spawn"
|
||||
_COLLAB_REPO="OpenRouterLabs/spawn"
|
||||
|
||||
# Refresh the collaborator cache if stale or missing
|
||||
_refresh_collaborator_cache() {
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ git branch -r --format='%(refname:short) %(committerdate:relative)' | grep -v 'o
|
|||
### Step 4: Get branches with open PRs (protected)
|
||||
|
||||
```bash
|
||||
gh pr list --repo OpenRouterTeam/spawn --state open --json headRefName --jq '.[].headRefName'
|
||||
gh pr list --repo OpenRouterLabs/spawn --state open --json headRefName --jq '.[].headRefName'
|
||||
```
|
||||
|
||||
Any branch with an open PR MUST be skipped. Never delete a branch that has an open PR.
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ Subsequent thread replies in tracked threads auto-trigger new Claude Code runs.
|
|||
| `SLACK_BOT_TOKEN` | Bot User OAuth Token (`xoxb-...`) |
|
||||
| `SLACK_APP_TOKEN` | App-Level Token for Socket Mode (`xapp-...`) |
|
||||
| `SLACK_CHANNEL_ID` | Channel ID to listen in (e.g. `C0123456789`) |
|
||||
| `GITHUB_REPO` | Target repo context (default: `OpenRouterTeam/spawn`) |
|
||||
| `GITHUB_REPO` | Target repo context (default: `OpenRouterLabs/spawn`) |
|
||||
| `REPO_ROOT` | Working directory for Claude Code (default: cwd) |
|
||||
|
||||
GitHub auth uses the `gh` CLI — run `gh auth login` before starting.
|
||||
|
|
@ -59,7 +59,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|||
export SLACK_BOT_TOKEN="xoxb-YOUR-BOT-TOKEN"
|
||||
export SLACK_APP_TOKEN="xapp-YOUR-APP-TOKEN"
|
||||
export SLACK_CHANNEL_ID="C0000000000"
|
||||
export GITHUB_REPO="OpenRouterTeam/spawn"
|
||||
export GITHUB_REPO="OpenRouterLabs/spawn"
|
||||
export REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
|
||||
|
||||
exec bun run "${SCRIPT_DIR}/main.ts"
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ type SlackClient = InstanceType<typeof App>["client"];
|
|||
|
||||
const SLACK_BOT_TOKEN = process.env.SLACK_BOT_TOKEN ?? "";
|
||||
const SLACK_APP_TOKEN = process.env.SLACK_APP_TOKEN ?? "";
|
||||
const GITHUB_REPO = process.env.GITHUB_REPO ?? "OpenRouterTeam/spawn";
|
||||
const GITHUB_REPO = process.env.GITHUB_REPO ?? "OpenRouterLabs/spawn";
|
||||
const TRIGGER_SECRET = process.env.TRIGGER_SECRET ?? "";
|
||||
const GROWTH_TRIGGER_URL = process.env.GROWTH_TRIGGER_URL ?? "";
|
||||
const GROWTH_REPLY_SECRET = process.env.GROWTH_REPLY_SECRET ?? "";
|
||||
|
|
|
|||
|
|
@ -332,10 +332,10 @@ describe("extractToolHint", () => {
|
|||
it("extracts command from input", () => {
|
||||
const block: Record<string, unknown> = {
|
||||
input: {
|
||||
command: "gh issue list --repo OpenRouterTeam/spawn",
|
||||
command: "gh issue list --repo OpenRouterLabs/spawn",
|
||||
},
|
||||
};
|
||||
expect(extractToolHint(block)).toBe("gh issue list --repo OpenRouterTeam/spawn");
|
||||
expect(extractToolHint(block)).toBe("gh issue list --repo OpenRouterLabs/spawn");
|
||||
});
|
||||
|
||||
it("extracts pattern from input", () => {
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ async function refreshIconsFor(
|
|||
const contentType = res.headers.get("content-type")?.split(";")[0] ?? "";
|
||||
const ext = EXT_MAP[contentType] ?? src.ext;
|
||||
const outPath = resolve(ROOT, `${assetDir}/${id}.${ext}`);
|
||||
const rawUrl = `https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/${assetDir}/${id}.${ext}`;
|
||||
const rawUrl = `https://raw.githubusercontent.com/OpenRouterLabs/spawn/main/${assetDir}/${id}.${ext}`;
|
||||
|
||||
if (dryRun) {
|
||||
console.log(` [dry-run] ${id}: would download ${src.url} → ${outPath}`);
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ All cloud provisioning and agent setup logic lives in TypeScript under `packages
|
|||
When you encounter bugs, stale references, broken functionality, or architectural issues that are **outside the scope of your current task**, file a GitHub issue immediately rather than ignoring them or trying to fix everything at once:
|
||||
|
||||
```bash
|
||||
gh issue create --repo OpenRouterTeam/spawn --title "bug: <brief description>" --body "<details>"
|
||||
gh issue create --repo OpenRouterLabs/spawn --title "bug: <brief description>" --body "<details>"
|
||||
```
|
||||
|
||||
Examples of when to file:
|
||||
|
|
|
|||
14
README.md
14
README.md
|
|
@ -332,7 +332,7 @@ If an agent fails to install or launch on a cloud:
|
|||
- **Rerun last session**: `spawn last` or `spawn rerun`
|
||||
- **Check version**: `spawn version` shows CLI version and cache status
|
||||
- **Update spawn**: `spawn update` checks for the latest version
|
||||
- **Report bugs**: Open an issue at https://github.com/OpenRouterTeam/spawn/issues
|
||||
- **Report bugs**: Open an issue at https://github.com/OpenRouterLabs/spawn/issues
|
||||
|
||||
## Matrix
|
||||
|
||||
|
|
@ -341,7 +341,7 @@ If an agent fails to install or launch on a cloud:
|
|||
| [**Claude Code**](https://claude.ai) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| [**OpenClaw**](https://github.com/openclaw/openclaw) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| [**Codex CLI**](https://github.com/openai/codex) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| [**OpenCode**](https://github.com/sst/opencode) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| [**OpenCode**](https://github.com/anomalyco/opencode) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| [**Kilo Code**](https://github.com/Kilo-Org/kilocode) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| [**Hermes Agent**](https://github.com/NousResearch/hermes-agent) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| [**Junie**](https://www.jetbrains.com/junie/) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
|
|
@ -362,7 +362,7 @@ Scripts work standalone (`bash <(curl ...)`) or through the CLI.
|
|||
## Development
|
||||
|
||||
```bash
|
||||
git clone https://github.com/OpenRouterTeam/spawn.git
|
||||
git clone https://github.com/OpenRouterLabs/spawn.git
|
||||
cd spawn
|
||||
git config core.hooksPath .githooks
|
||||
```
|
||||
|
|
@ -400,7 +400,7 @@ Pick any agent + cloud combination from the matrix and try it out:
|
|||
spawn claude hetzner # or any combination
|
||||
```
|
||||
|
||||
If something breaks, hangs, or behaves unexpectedly, open an issue using the [bug report template](https://github.com/OpenRouterTeam/spawn/issues/new?template=bug_report.yml). Include:
|
||||
If something breaks, hangs, or behaves unexpectedly, open an issue using the [bug report template](https://github.com/OpenRouterLabs/spawn/issues/new?template=bug_report.yml). Include:
|
||||
|
||||
- The exact command you ran
|
||||
- The cloud provider and agent
|
||||
|
|
@ -411,9 +411,9 @@ If something breaks, hangs, or behaves unexpectedly, open an issue using the [bu
|
|||
|
||||
Want to see a specific cloud provider or agent supported? Use the dedicated templates:
|
||||
|
||||
- [Request a cloud provider](https://github.com/OpenRouterTeam/spawn/issues/new?template=cloud_request.yml)
|
||||
- [Request an agent](https://github.com/OpenRouterTeam/spawn/issues/new?template=agent_request.yml)
|
||||
- [Request a CLI feature](https://github.com/OpenRouterTeam/spawn/issues/new?template=cli_feature_request.yml)
|
||||
- [Request a cloud provider](https://github.com/OpenRouterLabs/spawn/issues/new?template=cloud_request.yml)
|
||||
- [Request an agent](https://github.com/OpenRouterLabs/spawn/issues/new?template=agent_request.yml)
|
||||
- [Request a CLI feature](https://github.com/OpenRouterLabs/spawn/issues/new?template=cli_feature_request.yml)
|
||||
|
||||
Requests with real-world use cases get prioritized.
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
"type": "tool_use",
|
||||
"id": "toolu_01ABC",
|
||||
"name": "Bash",
|
||||
"input": { "command": "gh issue list --repo OpenRouterTeam/spawn --state open --limit 5" }
|
||||
"input": { "command": "gh issue list --repo OpenRouterLabs/spawn --state open --limit 5" }
|
||||
}
|
||||
],
|
||||
"model": "claude-sonnet-4-20250514",
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
"bypassPermissionsModeAccepted": true
|
||||
}
|
||||
},
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/assets/agents/claude.png",
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterLabs/spawn/main/assets/agents/claude.png",
|
||||
"featured_cloud": [
|
||||
"digitalocean",
|
||||
"sprite"
|
||||
|
|
@ -67,7 +67,7 @@
|
|||
"default": "openrouter/auto"
|
||||
}
|
||||
},
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/assets/agents/openclaw.png",
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterLabs/spawn/main/assets/agents/openclaw.png",
|
||||
"featured_cloud": [
|
||||
"digitalocean",
|
||||
"sprite"
|
||||
|
|
@ -101,7 +101,7 @@
|
|||
"OPENROUTER_API_KEY": "${OPENROUTER_API_KEY}"
|
||||
},
|
||||
"notes": "Works with OpenRouter via OPENAI_BASE_URL override pointing to openrouter.ai/api/v1",
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/assets/agents/codex.png",
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterLabs/spawn/main/assets/agents/codex.png",
|
||||
"featured_cloud": [
|
||||
"digitalocean",
|
||||
"sprite"
|
||||
|
|
@ -126,20 +126,20 @@
|
|||
"opencode": {
|
||||
"name": "OpenCode",
|
||||
"description": "AI coding agent built for the terminal with TUI",
|
||||
"url": "https://github.com/sst/opencode",
|
||||
"url": "https://github.com/anomalyco/opencode",
|
||||
"install": "curl -fsSL https://opencode.ai/install | bash",
|
||||
"launch": "opencode",
|
||||
"env": {
|
||||
"OPENROUTER_API_KEY": "${OPENROUTER_API_KEY}"
|
||||
},
|
||||
"notes": "Natively supports OpenRouter via OPENROUTER_API_KEY env var. Go-based TUI using Bubble Tea.",
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/assets/agents/opencode.png",
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterLabs/spawn/main/assets/agents/opencode.png",
|
||||
"featured_cloud": [
|
||||
"digitalocean",
|
||||
"sprite"
|
||||
],
|
||||
"creator": "SST",
|
||||
"repo": "sst/opencode",
|
||||
"repo": "anomalyco/opencode",
|
||||
"license": "MIT",
|
||||
"created": "2025-04",
|
||||
"added": "2025-08",
|
||||
|
|
@ -167,7 +167,7 @@
|
|||
"OPENROUTER_API_KEY": "${OPENROUTER_API_KEY}"
|
||||
},
|
||||
"notes": "Natively supports OpenRouter as a provider via KILO_PROVIDER_TYPE=openrouter. CLI installable via npm as @kilocode/cli, invocable as 'kilocode' or 'kilo'.",
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/assets/agents/kilocode.png",
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterLabs/spawn/main/assets/agents/kilocode.png",
|
||||
"featured_cloud": [
|
||||
"digitalocean",
|
||||
"sprite"
|
||||
|
|
@ -202,7 +202,7 @@
|
|||
"OPENAI_API_KEY": "${OPENROUTER_API_KEY}"
|
||||
},
|
||||
"notes": "Natively supports OpenRouter via OPENROUTER_API_KEY. Also works via OPENAI_BASE_URL + OPENAI_API_KEY for OpenAI-compatible mode. Installs Python 3.11 via uv. Ships a local web dashboard (port 9119) for configuration, session monitoring, skill browsing, and gateway management — auto-exposed via SSH tunnel when run through spawn.",
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/assets/agents/hermes.png",
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterLabs/spawn/main/assets/agents/hermes.png",
|
||||
"featured_cloud": [
|
||||
"digitalocean",
|
||||
"sprite"
|
||||
|
|
@ -236,7 +236,7 @@
|
|||
"OPENROUTER_API_KEY": "${OPENROUTER_API_KEY}"
|
||||
},
|
||||
"notes": "Natively supports OpenRouter via JUNIE_OPENROUTER_API_KEY. Subagent tasks may require GPT-4.1 Mini, GPT-4.1, or GPT-5 models to be enabled on your OpenRouter account.",
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/assets/agents/junie.png",
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterLabs/spawn/main/assets/agents/junie.png",
|
||||
"featured_cloud": [
|
||||
"digitalocean",
|
||||
"sprite"
|
||||
|
|
@ -269,7 +269,7 @@
|
|||
"OPENROUTER_API_KEY": "${OPENROUTER_API_KEY}"
|
||||
},
|
||||
"notes": "Natively supports OpenRouter as a provider via OPENROUTER_API_KEY. The CLI command is 'pi'. Config lives in ~/.pi/agent/. Also known as shittycodingagent.ai.",
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/assets/agents/pi.png",
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterLabs/spawn/main/assets/agents/pi.png",
|
||||
"featured_cloud": [
|
||||
"digitalocean",
|
||||
"sprite"
|
||||
|
|
@ -318,7 +318,7 @@
|
|||
}
|
||||
},
|
||||
"notes": "Routes through OpenRouter via a local ConnectRPC-to-REST translation proxy (Caddy + Node.js). The proxy intercepts Cursor's proprietary protobuf protocol, translates to OpenAI-compatible API calls, and streams responses back. Binary installs to ~/.local/bin/agent.",
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/assets/agents/cursor.png",
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterLabs/spawn/main/assets/agents/cursor.png",
|
||||
"featured_cloud": [
|
||||
"digitalocean",
|
||||
"sprite"
|
||||
|
|
@ -355,7 +355,7 @@
|
|||
"OPENAI_BASE_URL": "https://openrouter.ai/api/v1"
|
||||
},
|
||||
"notes": "Web GUI that spawns Claude Code and Codex as subprocesses via node-pty. OpenRouter integration works through inherited env vars on the child agent processes. Requires Node.js 22+. Default port 3773.",
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/assets/agents/t3code.png",
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterLabs/spawn/main/assets/agents/t3code.png",
|
||||
"featured_cloud": [
|
||||
"digitalocean",
|
||||
"sprite"
|
||||
|
|
@ -384,7 +384,7 @@
|
|||
"name": "Local Machine",
|
||||
"price": "Free",
|
||||
"description": "Your computer — no account or payment needed",
|
||||
"url": "https://github.com/OpenRouterTeam/spawn",
|
||||
"url": "https://github.com/OpenRouterLabs/spawn",
|
||||
"type": "local",
|
||||
"auth": "none",
|
||||
"provision_method": "none (local execution)",
|
||||
|
|
@ -396,7 +396,7 @@
|
|||
"name": "Local Sandbox",
|
||||
"price": "Free",
|
||||
"description": "Your computer, in a throwaway Docker container — no account or payment needed",
|
||||
"url": "https://github.com/OpenRouterTeam/spawn",
|
||||
"url": "https://github.com/OpenRouterLabs/spawn",
|
||||
"type": "local",
|
||||
"auth": "none",
|
||||
"provision_method": "docker run (local container)",
|
||||
|
|
@ -419,7 +419,7 @@
|
|||
"location": "nbg1",
|
||||
"image": "ubuntu-24.04"
|
||||
},
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/assets/clouds/hetzner.png"
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterLabs/spawn/main/assets/clouds/hetzner.png"
|
||||
},
|
||||
"aws": {
|
||||
"name": "AWS Lightsail",
|
||||
|
|
@ -437,7 +437,7 @@
|
|||
"blueprint": "ubuntu_24_04"
|
||||
},
|
||||
"notes": "Uses 'ubuntu' user instead of 'root'. Requires AWS CLI installed and configured.",
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/assets/clouds/aws.png"
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterLabs/spawn/main/assets/clouds/aws.png"
|
||||
},
|
||||
"digitalocean": {
|
||||
"name": "DigitalOcean",
|
||||
|
|
@ -454,7 +454,7 @@
|
|||
"region": "nyc3",
|
||||
"image": "ubuntu-24-04-x64"
|
||||
},
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/assets/clouds/digitalocean.png"
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterLabs/spawn/main/assets/clouds/digitalocean.png"
|
||||
},
|
||||
"gcp": {
|
||||
"name": "GCP Compute Engine",
|
||||
|
|
@ -472,7 +472,7 @@
|
|||
"image_family": "ubuntu-2404-lts-amd64"
|
||||
},
|
||||
"notes": "Uses current username for SSH. Requires gcloud CLI installed and configured.",
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/assets/clouds/gcp.png"
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterLabs/spawn/main/assets/clouds/gcp.png"
|
||||
},
|
||||
"daytona": {
|
||||
"name": "Daytona",
|
||||
|
|
@ -489,7 +489,7 @@
|
|||
"size": "small"
|
||||
},
|
||||
"notes": "Uses the Daytona SDK for sandbox lifecycle, file transfer, and signed preview URLs. SSH access tokens are minted on demand and never persisted.",
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/assets/clouds/daytona.png"
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterLabs/spawn/main/assets/clouds/daytona.png"
|
||||
},
|
||||
"sprite": {
|
||||
"name": "Sprite",
|
||||
|
|
@ -501,7 +501,7 @@
|
|||
"provision_method": "sprite create",
|
||||
"exec_method": "sprite exec",
|
||||
"interactive_method": "sprite exec -tty",
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/assets/clouds/sprite.png"
|
||||
"icon": "https://raw.githubusercontent.com/OpenRouterLabs/spawn/main/assets/clouds/sprite.png"
|
||||
}
|
||||
},
|
||||
"matrix": {
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ The TypeScript CLI (`src/*.ts`) provides:
|
|||
### Quick Install
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/sh/cli/install.sh | bash
|
||||
curl -fsSL https://raw.githubusercontent.com/OpenRouterLabs/spawn/main/sh/cli/install.sh | bash
|
||||
```
|
||||
|
||||
The installer will:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@openrouter/spawn",
|
||||
"version": "1.1.0",
|
||||
"version": "1.1.1",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
"spawn": "cli.js"
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ const RELEASE_PAYLOAD = {
|
|||
{
|
||||
name: "spawn-agent-openclaw-x86_64-20260305.tar.gz",
|
||||
browser_download_url:
|
||||
"https://github.com/OpenRouterTeam/spawn/releases/download/agent-openclaw-latest/spawn-agent-openclaw-x86_64-20260305.tar.gz",
|
||||
"https://github.com/OpenRouterLabs/spawn/releases/download/agent-openclaw-latest/spawn-agent-openclaw-x86_64-20260305.tar.gz",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
@ -178,7 +178,7 @@ describe("tryTarballInstall", () => {
|
|||
{
|
||||
name: "spawn-agent-claude-x86_64-20260305.tar.gz",
|
||||
browser_download_url:
|
||||
"https://github.com/OpenRouterTeam/spawn/releases/download/agent-claude-latest/spawn-agent-claude-x86_64-20260305.tar.gz",
|
||||
"https://github.com/OpenRouterLabs/spawn/releases/download/agent-claude-latest/spawn-agent-claude-x86_64-20260305.tar.gz",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
@ -199,7 +199,7 @@ describe("tryTarballInstall", () => {
|
|||
{
|
||||
name: "spawn-agent-claude-arm64-20260305.tar.gz",
|
||||
browser_download_url:
|
||||
"https://github.com/OpenRouterTeam/spawn/releases/download/agent-claude-latest/spawn-agent-claude-arm64-20260305.tar.gz",
|
||||
"https://github.com/OpenRouterLabs/spawn/releases/download/agent-claude-latest/spawn-agent-claude-arm64-20260305.tar.gz",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
@ -220,12 +220,12 @@ describe("tryTarballInstall", () => {
|
|||
{
|
||||
name: "spawn-agent-claude-x86_64-20260305.tar.gz",
|
||||
browser_download_url:
|
||||
"https://github.com/OpenRouterTeam/spawn/releases/download/agent-claude-latest/spawn-agent-claude-x86_64-20260305.tar.gz",
|
||||
"https://github.com/OpenRouterLabs/spawn/releases/download/agent-claude-latest/spawn-agent-claude-x86_64-20260305.tar.gz",
|
||||
},
|
||||
{
|
||||
name: "spawn-agent-claude-arm64-20260305.tar.gz",
|
||||
browser_download_url:
|
||||
"https://github.com/OpenRouterTeam/spawn/releases/download/agent-claude-latest/spawn-agent-claude-arm64-20260305.tar.gz",
|
||||
"https://github.com/OpenRouterLabs/spawn/releases/download/agent-claude-latest/spawn-agent-claude-arm64-20260305.tar.gz",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -49,6 +49,23 @@ let fetchCalls: Array<{
|
|||
url: string;
|
||||
}> = [];
|
||||
|
||||
/**
|
||||
* Filter fetchCalls down to just the spawn-script download URLs.
|
||||
*
|
||||
* cmdRun fires background telemetry (PostHog `us.i.posthog.com/batch/`) and
|
||||
* feature-flag (`/decide/`) requests that flush asynchronously. In a full-suite
|
||||
* run these can land mid-test and pollute fetchCalls, so we must assert on the
|
||||
* script-host URLs we actually care about rather than "everything that isn't the
|
||||
* manifest". See: the cmdrun-happy-path flake fix.
|
||||
*/
|
||||
function scriptDownloadFetches() {
|
||||
// Script URLs always end in `.sh` (primary: openrouter.ai/labs/spawn/<cloud>/<agent>.sh,
|
||||
// fallback: raw.githubusercontent.com/.../sh/<cloud>/<agent>.sh). The manifest
|
||||
// (`manifest.json`) and telemetry/feature-flag calls never do, so this cleanly
|
||||
// isolates the download requests under test.
|
||||
return fetchCalls.filter((c) => c.url.endsWith(".sh"));
|
||||
}
|
||||
|
||||
function mockFetchForDownload(opts: {
|
||||
primaryOk?: boolean;
|
||||
fallbackOk?: boolean;
|
||||
|
|
@ -171,7 +188,7 @@ describe("cmdRun happy-path pipeline", () => {
|
|||
await cmdRun("claude", "sprite");
|
||||
|
||||
// Should have fetched the manifest + the primary script URL
|
||||
const scriptFetches = fetchCalls.filter((c) => !c.url.includes("manifest.json"));
|
||||
const scriptFetches = scriptDownloadFetches();
|
||||
expect(scriptFetches.length).toBe(1);
|
||||
expect(scriptFetches[0].url).toContain("openrouter.ai");
|
||||
});
|
||||
|
|
@ -215,7 +232,7 @@ describe("cmdRun happy-path pipeline", () => {
|
|||
await cmdRun("claude", "sprite");
|
||||
|
||||
// Should have fetched manifest + primary (failed) + fallback (success)
|
||||
const scriptFetches = fetchCalls.filter((c) => !c.url.includes("manifest.json"));
|
||||
const scriptFetches = scriptDownloadFetches();
|
||||
expect(scriptFetches.length).toBe(2);
|
||||
expect(scriptFetches[0].url).toContain("openrouter.ai");
|
||||
expect(scriptFetches[1].url).toContain("raw.githubusercontent.com");
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ describe("Commands Display Output", () => {
|
|||
it("should show repository URL", () => {
|
||||
cmdHelp();
|
||||
const output = consoleMocks.log.mock.calls.map((c: unknown[]) => c.join(" ")).join("\n");
|
||||
expect(output).toContain("OpenRouterTeam/spawn");
|
||||
expect(output).toContain("OpenRouterLabs/spawn");
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { afterEach, beforeEach, describe, expect, it, mock, spyOn } from "bun:test";
|
||||
import { isString } from "@openrouter/spawn-shared";
|
||||
import { mockBunSpawn, mockClackPrompts } from "./test-helpers";
|
||||
|
||||
mockClackPrompts();
|
||||
|
|
@ -585,11 +586,21 @@ describe("hetzner/createServer", () => {
|
|||
},
|
||||
},
|
||||
};
|
||||
let callCount = 0;
|
||||
global.fetch = mock(() => {
|
||||
callCount++;
|
||||
if (callCount <= 1) {
|
||||
// Token validation
|
||||
// Route responses by HTTP method + endpoint rather than a fragile global
|
||||
// call-counter. The previous call-count-keyed mock drifted in full-suite
|
||||
// runs (the resource-limit 403 landed on the wrong call slot, so cleanup
|
||||
// never fired and the raw 403 propagated). Routing by request makes the
|
||||
// mock order-independent and robust to any extra/interleaved fetches.
|
||||
let createAttempts = 0;
|
||||
let listIpCalls = 0;
|
||||
let deleteIpCalls = 0;
|
||||
global.fetch = mock((input: string | URL | Request, init?: RequestInit) => {
|
||||
const url = isString(input) ? input : input instanceof URL ? input.href : input.url;
|
||||
const method = (init?.method ?? (input instanceof Request ? input.method : "GET")).toUpperCase();
|
||||
const path = url.replace("https://api.hetzner.cloud/v1", "");
|
||||
|
||||
// Token validation (GET /servers?per_page=1) and any other server reads
|
||||
if (method === "GET" && path.startsWith("/servers")) {
|
||||
return Promise.resolve(
|
||||
new Response(
|
||||
JSON.stringify({
|
||||
|
|
@ -598,8 +609,8 @@ describe("hetzner/createServer", () => {
|
|||
),
|
||||
);
|
||||
}
|
||||
if (callCount <= 2) {
|
||||
// SSH keys
|
||||
// SSH keys lookup
|
||||
if (method === "GET" && path.startsWith("/ssh_keys")) {
|
||||
return Promise.resolve(
|
||||
new Response(
|
||||
JSON.stringify({
|
||||
|
|
@ -608,24 +619,29 @@ describe("hetzner/createServer", () => {
|
|||
),
|
||||
);
|
||||
}
|
||||
if (callCount <= 3) {
|
||||
// First create attempt — resource_limit_exceeded (HTTP 403)
|
||||
return Promise.resolve(
|
||||
new Response(
|
||||
JSON.stringify({
|
||||
error: {
|
||||
code: "resource_limit_exceeded",
|
||||
message: "primary_ip_limit",
|
||||
// Create server: first attempt fails with resource_limit, retry succeeds
|
||||
if (method === "POST" && path === "/servers") {
|
||||
createAttempts++;
|
||||
if (createAttempts === 1) {
|
||||
return Promise.resolve(
|
||||
new Response(
|
||||
JSON.stringify({
|
||||
error: {
|
||||
code: "resource_limit_exceeded",
|
||||
message: "primary_ip_limit",
|
||||
},
|
||||
}),
|
||||
{
|
||||
status: 403,
|
||||
},
|
||||
}),
|
||||
{
|
||||
status: 403,
|
||||
},
|
||||
),
|
||||
);
|
||||
),
|
||||
);
|
||||
}
|
||||
return Promise.resolve(new Response(JSON.stringify(serverResp)));
|
||||
}
|
||||
if (callCount <= 4) {
|
||||
// List primary IPs for cleanup
|
||||
// List primary IPs for cleanup — one orphaned (assignee 0), one attached
|
||||
if (method === "GET" && path.startsWith("/primary_ips")) {
|
||||
listIpCalls++;
|
||||
return Promise.resolve(
|
||||
new Response(
|
||||
JSON.stringify({
|
||||
|
|
@ -645,31 +661,40 @@ describe("hetzner/createServer", () => {
|
|||
),
|
||||
);
|
||||
}
|
||||
if (callCount <= 5) {
|
||||
// Delete orphaned IP 100
|
||||
// Delete orphaned primary IP
|
||||
if (method === "DELETE" && path.startsWith("/primary_ips/")) {
|
||||
deleteIpCalls++;
|
||||
return Promise.resolve(
|
||||
new Response("", {
|
||||
status: 204,
|
||||
}),
|
||||
);
|
||||
}
|
||||
// Retry create — success
|
||||
return Promise.resolve(new Response(JSON.stringify(serverResp)));
|
||||
return Promise.resolve(
|
||||
new Response(JSON.stringify({}), {
|
||||
status: 404,
|
||||
}),
|
||||
);
|
||||
});
|
||||
const { ensureHcloudToken, createServer } = await import("../hetzner/hetzner");
|
||||
await ensureHcloudToken();
|
||||
const conn = await createServer("test-retry", "cx23", "fsn1");
|
||||
expect(conn.ip).toBe("10.0.0.5");
|
||||
// Should have called: token(1), ssh_keys(2), create-fail(3), list-ips(4), delete-ip(5), create-ok(6)
|
||||
expect(callCount).toBeGreaterThanOrEqual(6);
|
||||
// The retry flow must have: failed once, cleaned up an orphaned IP, retried.
|
||||
expect(createAttempts).toBe(2);
|
||||
expect(listIpCalls).toBeGreaterThanOrEqual(1);
|
||||
expect(deleteIpCalls).toBe(1);
|
||||
});
|
||||
|
||||
it("throws with guidance when resource limit hit and no orphaned IPs to clean", async () => {
|
||||
process.env.HCLOUD_TOKEN = "test-token";
|
||||
let callCount = 0;
|
||||
global.fetch = mock(() => {
|
||||
callCount++;
|
||||
if (callCount <= 1) {
|
||||
// Route by method + endpoint (order-independent — see the retry test above).
|
||||
global.fetch = mock((input: string | URL | Request, init?: RequestInit) => {
|
||||
const url = isString(input) ? input : input instanceof URL ? input.href : input.url;
|
||||
const method = (init?.method ?? (input instanceof Request ? input.method : "GET")).toUpperCase();
|
||||
const path = url.replace("https://api.hetzner.cloud/v1", "");
|
||||
|
||||
if (method === "GET" && path.startsWith("/servers")) {
|
||||
return Promise.resolve(
|
||||
new Response(
|
||||
JSON.stringify({
|
||||
|
|
@ -678,7 +703,7 @@ describe("hetzner/createServer", () => {
|
|||
),
|
||||
);
|
||||
}
|
||||
if (callCount <= 2) {
|
||||
if (method === "GET" && path.startsWith("/ssh_keys")) {
|
||||
return Promise.resolve(
|
||||
new Response(
|
||||
JSON.stringify({
|
||||
|
|
@ -687,8 +712,8 @@ describe("hetzner/createServer", () => {
|
|||
),
|
||||
);
|
||||
}
|
||||
if (callCount <= 3) {
|
||||
// Create fails with resource_limit_exceeded
|
||||
// Create always fails with resource_limit_exceeded
|
||||
if (method === "POST" && path === "/servers") {
|
||||
return Promise.resolve(
|
||||
new Response(
|
||||
JSON.stringify({
|
||||
|
|
@ -703,19 +728,26 @@ describe("hetzner/createServer", () => {
|
|||
),
|
||||
);
|
||||
}
|
||||
// List primary IPs — all attached (none orphaned)
|
||||
// List primary IPs — all attached (none orphaned to clean up)
|
||||
if (method === "GET" && path.startsWith("/primary_ips")) {
|
||||
return Promise.resolve(
|
||||
new Response(
|
||||
JSON.stringify({
|
||||
primary_ips: [
|
||||
{
|
||||
id: 100,
|
||||
ip: "1.2.3.4",
|
||||
assignee_id: 42,
|
||||
},
|
||||
],
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
return Promise.resolve(
|
||||
new Response(
|
||||
JSON.stringify({
|
||||
primary_ips: [
|
||||
{
|
||||
id: 100,
|
||||
ip: "1.2.3.4",
|
||||
assignee_id: 42,
|
||||
},
|
||||
],
|
||||
}),
|
||||
),
|
||||
new Response(JSON.stringify({}), {
|
||||
status: 404,
|
||||
}),
|
||||
);
|
||||
});
|
||||
const { ensureHcloudToken, createServer } = await import("../hetzner/hetzner");
|
||||
|
|
|
|||
|
|
@ -37,6 +37,23 @@ import { tryCatch } from "@openrouter/spawn-shared";
|
|||
//
|
||||
// We clean up before and after every test run to keep the working tree tidy.
|
||||
|
||||
// ── Disable telemetry / analytics network calls in tests ────────────────────
|
||||
//
|
||||
// `bun test` does NOT set NODE_ENV or BUN_ENV, so without this the telemetry
|
||||
// module (shared/telemetry.ts) sees `_enabled = true` and fires real
|
||||
// fire-and-forget PostHog `fetch` calls (https://us.i.posthog.com/batch/) plus
|
||||
// feature-flag `/decide/` requests during tests. Because those land on the
|
||||
// SAME `global.fetch` that tests mock, they:
|
||||
// - pollute fetch-call tracking arrays (e.g. cmdrun-happy-path counted 10
|
||||
// "downloads" instead of 1 when batched PostHog flushes interleaved), and
|
||||
// - drift sequential `callCount`-keyed mocks (e.g. hetzner-cov's
|
||||
// resource-limit retry test), and can make real network calls.
|
||||
// Setting these env vars before any module loads hard-disables telemetry for
|
||||
// the whole suite, removing the shared root cause of those flakes.
|
||||
process.env.NODE_ENV = "test";
|
||||
process.env.BUN_ENV = "test";
|
||||
process.env.SPAWN_TELEMETRY = "0";
|
||||
|
||||
const REAL_HOME = process.env.HOME ?? "";
|
||||
|
||||
function cleanupStrayTestFiles(): void {
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ describe("maybeShowStarPrompt", () => {
|
|||
|
||||
expect(logMessageSpy).toHaveBeenCalledTimes(1);
|
||||
const msg = logMessageSpy.mock.calls[0]?.[0];
|
||||
expect(isString(msg) && msg.includes("github.com/OpenRouterTeam/spawn")).toBe(true);
|
||||
expect(isString(msg) && msg.includes("github.com/OpenRouterLabs/spawn")).toBe(true);
|
||||
});
|
||||
|
||||
it("saves starPromptShownAt to preferences after showing", () => {
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ export function buildReadmeTemplate(): string {
|
|||
return [
|
||||
"# __NAME__",
|
||||
"",
|
||||
"Exported from a [spawn](https://github.com/OpenRouterTeam/spawn) session on `__CLOUD__`.",
|
||||
"Exported from a [spawn](https://github.com/OpenRouterLabs/spawn) session on `__CLOUD__`.",
|
||||
"",
|
||||
"## Quickstart",
|
||||
"",
|
||||
|
|
|
|||
|
|
@ -65,14 +65,14 @@ export const EXIT_CODE_GUIDANCE: Record<number, ExitCodeEntry> = {
|
|||
lines: [
|
||||
" - A downloaded binary may lack execute permissions",
|
||||
" - The script may require root/sudo access",
|
||||
` - Report it if this persists: ${pc.cyan("https://github.com/OpenRouterTeam/spawn/issues")}`,
|
||||
` - Report it if this persists: ${pc.cyan("https://github.com/OpenRouterLabs/spawn/issues")}`,
|
||||
],
|
||||
includeDashboard: false,
|
||||
},
|
||||
2: {
|
||||
header: "Shell syntax or argument error. This is likely a bug in the script.",
|
||||
lines: [
|
||||
` Report it at: ${pc.cyan("https://github.com/OpenRouterTeam/spawn/issues")}`,
|
||||
` Report it at: ${pc.cyan("https://github.com/OpenRouterLabs/spawn/issues")}`,
|
||||
],
|
||||
includeDashboard: false,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -497,7 +497,7 @@ function showVersion(): void {
|
|||
);
|
||||
const age = getCacheAge();
|
||||
console.log(pc.dim(` manifest cache: ${formatCacheAge(age)}`));
|
||||
console.log(pc.dim(" https://github.com/OpenRouterTeam/spawn"));
|
||||
console.log(pc.dim(" https://github.com/OpenRouterLabs/spawn"));
|
||||
console.log(pc.dim(` Run ${pc.cyan("spawn feedback")} to tell us what to improve.`));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ export interface Manifest {
|
|||
|
||||
// ── Constants ──────────────────────────────────────────────────────────────────
|
||||
|
||||
const REPO = "OpenRouterTeam/spawn";
|
||||
const REPO = "OpenRouterLabs/spawn";
|
||||
const RAW_BASE = `https://raw.githubusercontent.com/${REPO}/main` as const;
|
||||
/** Primary CDN for shell scripts — maps openrouter.ai/labs/spawn/* → repo sh/* */
|
||||
const SPAWN_CDN = "https://openrouter.ai/labs/spawn" as const;
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ export function validateScriptContent(script: string): void {
|
|||
"Security check failed: the downloaded script contains a dangerous pattern.\n\n" +
|
||||
`Pattern detected: ${description}\n\n` +
|
||||
"This is unexpected and may indicate the file was tampered with or corrupted.\n" +
|
||||
"Please report this at: https://github.com/OpenRouterTeam/spawn/issues",
|
||||
"Please report this at: https://github.com/OpenRouterLabs/spawn/issues",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -159,7 +159,7 @@ export function validateScriptContent(script: string): void {
|
|||
" 1. Check your internet connection and try again\n" +
|
||||
" 2. Run 'spawn matrix' to verify the combination is marked as implemented\n" +
|
||||
" 3. Wait a few moments (the script may be deploying) and retry\n" +
|
||||
" 4. If the issue persists, report it: https://github.com/OpenRouterTeam/spawn/issues",
|
||||
" 4. If the issue persists, report it: https://github.com/OpenRouterLabs/spawn/issues",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -756,7 +756,7 @@ export async function startHermesDashboard(runner: CloudRunner): Promise<void> {
|
|||
// ─── OpenCode Install Command ────────────────────────────────────────────────
|
||||
|
||||
function openCodeInstallCmd(): string {
|
||||
return 'OC_ARCH=$(uname -m); case "$OC_ARCH" in aarch64) OC_ARCH=arm64;; x86_64) OC_ARCH=x64;; esac; OC_OS=$(uname -s | tr A-Z a-z); mkdir -p /tmp/opencode-install "$HOME/.opencode/bin" && curl --proto \'=https\' -fsSL -o /tmp/opencode-install/oc.tar.gz "https://github.com/sst/opencode/releases/latest/download/opencode-${OC_OS}-${OC_ARCH}.tar.gz" && if tar -tzf /tmp/opencode-install/oc.tar.gz | grep -qE \'(^/|\\.\\.)\'; then echo "Tarball contains unsafe paths" >&2; exit 1; fi && tar xzf /tmp/opencode-install/oc.tar.gz -C /tmp/opencode-install && mv /tmp/opencode-install/opencode "$HOME/.opencode/bin/" && rm -rf /tmp/opencode-install && for _rc in "$HOME/.bashrc" "$HOME/.profile" "$HOME/.bash_profile"; do grep -q ".opencode/bin" "$_rc" 2>/dev/null || echo \'export PATH="$HOME/.opencode/bin:$PATH"\' >> "$_rc"; done; { [ ! -f "$HOME/.zshrc" ] || grep -q ".opencode/bin" "$HOME/.zshrc" 2>/dev/null || echo \'export PATH="$HOME/.opencode/bin:$PATH"\' >> "$HOME/.zshrc"; }; export PATH="$HOME/.opencode/bin:$PATH"';
|
||||
return 'OC_ARCH=$(uname -m); case "$OC_ARCH" in aarch64) OC_ARCH=arm64;; x86_64) OC_ARCH=x64;; esac; OC_OS=$(uname -s | tr A-Z a-z); mkdir -p /tmp/opencode-install "$HOME/.opencode/bin" && curl --proto \'=https\' -fsSL -o /tmp/opencode-install/oc.tar.gz "https://github.com/anomalyco/opencode/releases/latest/download/opencode-${OC_OS}-${OC_ARCH}.tar.gz" && if tar -tzf /tmp/opencode-install/oc.tar.gz | grep -qE \'(^/|\\.\\.)\'; then echo "Tarball contains unsafe paths" >&2; exit 1; fi && tar xzf /tmp/opencode-install/oc.tar.gz -C /tmp/opencode-install && mv /tmp/opencode-install/opencode "$HOME/.opencode/bin/" && rm -rf /tmp/opencode-install && for _rc in "$HOME/.bashrc" "$HOME/.profile" "$HOME/.bash_profile"; do grep -q ".opencode/bin" "$_rc" 2>/dev/null || echo \'export PATH="$HOME/.opencode/bin:$PATH"\' >> "$_rc"; done; { [ ! -f "$HOME/.zshrc" ] || grep -q ".opencode/bin" "$HOME/.zshrc" 2>/dev/null || echo \'export PATH="$HOME/.opencode/bin:$PATH"\' >> "$HOME/.zshrc"; }; export PATH="$HOME/.opencode/bin:$PATH"';
|
||||
}
|
||||
|
||||
// ─── npm prefix helper ────────────────────────────────────────────────────────
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import * as v from "valibot";
|
|||
import { asyncTryCatch } from "./result.js";
|
||||
import { logDebug, logInfo, logStep, logWarn } from "./ui.js";
|
||||
|
||||
const REPO = "OpenRouterTeam/spawn";
|
||||
const REPO = "OpenRouterLabs/spawn";
|
||||
|
||||
/** Schema for a single GitHub Release asset. */
|
||||
const AssetSchema = v.object({
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ export function maybeShowStarPrompt(): void {
|
|||
}
|
||||
|
||||
// 3. Print the star message
|
||||
p.log.message("⭐ Enjoying Spawn? Star us on GitHub!\n https://github.com/OpenRouterTeam/spawn");
|
||||
p.log.message("⭐ Enjoying Spawn? Star us on GitHub!\n https://github.com/OpenRouterLabs/spawn");
|
||||
|
||||
// 4. Save the updated timestamp
|
||||
const merged = {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,6 @@ fi
|
|||
# Remote — download and run compiled TypeScript bundle
|
||||
AWS_JS=$(mktemp)
|
||||
trap 'rm -f "$AWS_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/aws-latest/aws.js" -o "$AWS_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/aws-latest/aws.js" -o "$AWS_JS" \
|
||||
|| { printf '\033[0;31mFailed to download aws.js\033[0m\n' >&2; exit 1; }
|
||||
exec bun run "$AWS_JS" claude "$@"
|
||||
|
|
|
|||
|
|
@ -21,6 +21,6 @@ fi
|
|||
# Remote — download and run compiled TypeScript bundle
|
||||
AWS_JS=$(mktemp)
|
||||
trap 'rm -f "$AWS_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/aws-latest/aws.js" -o "$AWS_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/aws-latest/aws.js" -o "$AWS_JS" \
|
||||
|| { printf '\033[0;31mFailed to download aws.js\033[0m\n' >&2; exit 1; }
|
||||
exec bun run "$AWS_JS" codex "$@"
|
||||
|
|
|
|||
|
|
@ -21,6 +21,6 @@ fi
|
|||
# Remote — download and run compiled TypeScript bundle
|
||||
AWS_JS=$(mktemp)
|
||||
trap 'rm -f "$AWS_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/aws-latest/aws.js" -o "$AWS_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/aws-latest/aws.js" -o "$AWS_JS" \
|
||||
|| { printf '\033[0;31mFailed to download aws.js\033[0m\n' >&2; exit 1; }
|
||||
exec bun run "$AWS_JS" cursor "$@"
|
||||
|
|
|
|||
|
|
@ -21,6 +21,6 @@ fi
|
|||
# Remote — download and run compiled TypeScript bundle
|
||||
AWS_JS=$(mktemp)
|
||||
trap 'rm -f "$AWS_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/aws-latest/aws.js" -o "$AWS_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/aws-latest/aws.js" -o "$AWS_JS" \
|
||||
|| { printf '\033[0;31mFailed to download aws.js\033[0m\n' >&2; exit 1; }
|
||||
exec bun run "$AWS_JS" hermes "$@"
|
||||
|
|
|
|||
|
|
@ -21,6 +21,6 @@ fi
|
|||
# Remote — download and run compiled TypeScript bundle
|
||||
AWS_JS=$(mktemp)
|
||||
trap 'rm -f "$AWS_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/aws-latest/aws.js" -o "$AWS_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/aws-latest/aws.js" -o "$AWS_JS" \
|
||||
|| { printf '\033[0;31mFailed to download aws.js\033[0m\n' >&2; exit 1; }
|
||||
exec bun run "$AWS_JS" junie "$@"
|
||||
|
|
|
|||
|
|
@ -21,6 +21,6 @@ fi
|
|||
# Remote — download and run compiled TypeScript bundle
|
||||
AWS_JS=$(mktemp)
|
||||
trap 'rm -f "$AWS_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/aws-latest/aws.js" -o "$AWS_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/aws-latest/aws.js" -o "$AWS_JS" \
|
||||
|| { printf '\033[0;31mFailed to download aws.js\033[0m\n' >&2; exit 1; }
|
||||
exec bun run "$AWS_JS" kilocode "$@"
|
||||
|
|
|
|||
|
|
@ -21,6 +21,6 @@ fi
|
|||
# Remote — download and run compiled TypeScript bundle
|
||||
AWS_JS=$(mktemp)
|
||||
trap 'rm -f "$AWS_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/aws-latest/aws.js" -o "$AWS_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/aws-latest/aws.js" -o "$AWS_JS" \
|
||||
|| { printf '\033[0;31mFailed to download aws.js\033[0m\n' >&2; exit 1; }
|
||||
exec bun run "$AWS_JS" openclaw "$@"
|
||||
|
|
|
|||
|
|
@ -21,6 +21,6 @@ fi
|
|||
# Remote — download and run compiled TypeScript bundle
|
||||
AWS_JS=$(mktemp)
|
||||
trap 'rm -f "$AWS_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/aws-latest/aws.js" -o "$AWS_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/aws-latest/aws.js" -o "$AWS_JS" \
|
||||
|| { printf '\033[0;31mFailed to download aws.js\033[0m\n' >&2; exit 1; }
|
||||
exec bun run "$AWS_JS" opencode "$@"
|
||||
|
|
|
|||
|
|
@ -21,6 +21,6 @@ fi
|
|||
# Remote — download and run compiled TypeScript bundle
|
||||
AWS_JS=$(mktemp)
|
||||
trap 'rm -f "$AWS_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/aws-latest/aws.js" -o "$AWS_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/aws-latest/aws.js" -o "$AWS_JS" \
|
||||
|| { printf '\033[0;31mFailed to download aws.js\033[0m\n' >&2; exit 1; }
|
||||
exec bun run "$AWS_JS" pi "$@"
|
||||
|
|
|
|||
|
|
@ -21,6 +21,6 @@ fi
|
|||
# Remote — download and run compiled TypeScript bundle
|
||||
AWS_JS=$(mktemp)
|
||||
trap 'rm -f "$AWS_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/aws-latest/aws.js" -o "$AWS_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/aws-latest/aws.js" -o "$AWS_JS" \
|
||||
|| { printf '\033[0;31mFailed to download aws.js\033[0m\n' >&2; exit 1; }
|
||||
exec bun run "$AWS_JS" t3code "$@"
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$SPAWN_REPO = "OpenRouterTeam/spawn"
|
||||
$SPAWN_REPO = "OpenRouterLabs/spawn"
|
||||
$SPAWN_RAW_BASE = "https://raw.githubusercontent.com/$SPAWN_REPO/main"
|
||||
$MIN_BUN_VERSION = [version]"1.2.0"
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
set -eo pipefail
|
||||
|
||||
SPAWN_REPO="OpenRouterTeam/spawn"
|
||||
SPAWN_REPO="OpenRouterLabs/spawn"
|
||||
SPAWN_CDN="https://openrouter.ai/labs/spawn"
|
||||
SPAWN_RAW_BASE="https://raw.githubusercontent.com/${SPAWN_REPO}/main"
|
||||
MIN_BUN_VERSION="1.2.0"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled daytona.js from GitHub release
|
||||
DAYTONA_JS=$(mktemp)
|
||||
trap 'rm -f "$DAYTONA_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/daytona-latest/daytona.js" -o "$DAYTONA_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/daytona-latest/daytona.js" -o "$DAYTONA_JS" \
|
||||
|| { printf '\033[0;31mFailed to download daytona.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$DAYTONA_JS" claude "$@"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled daytona.js from GitHub release
|
||||
DAYTONA_JS=$(mktemp)
|
||||
trap 'rm -f "$DAYTONA_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/daytona-latest/daytona.js" -o "$DAYTONA_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/daytona-latest/daytona.js" -o "$DAYTONA_JS" \
|
||||
|| { printf '\033[0;31mFailed to download daytona.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$DAYTONA_JS" codex "$@"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled daytona.js from GitHub release
|
||||
DAYTONA_JS=$(mktemp)
|
||||
trap 'rm -f "$DAYTONA_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/daytona-latest/daytona.js" -o "$DAYTONA_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/daytona-latest/daytona.js" -o "$DAYTONA_JS" \
|
||||
|| { printf '\033[0;31mFailed to download daytona.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$DAYTONA_JS" cursor "$@"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled daytona.js from GitHub release
|
||||
DAYTONA_JS=$(mktemp)
|
||||
trap 'rm -f "$DAYTONA_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/daytona-latest/daytona.js" -o "$DAYTONA_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/daytona-latest/daytona.js" -o "$DAYTONA_JS" \
|
||||
|| { printf '\033[0;31mFailed to download daytona.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$DAYTONA_JS" hermes "$@"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled daytona.js from GitHub release
|
||||
DAYTONA_JS=$(mktemp)
|
||||
trap 'rm -f "$DAYTONA_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/daytona-latest/daytona.js" -o "$DAYTONA_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/daytona-latest/daytona.js" -o "$DAYTONA_JS" \
|
||||
|| { printf '\033[0;31mFailed to download daytona.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$DAYTONA_JS" junie "$@"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled daytona.js from GitHub release
|
||||
DAYTONA_JS=$(mktemp)
|
||||
trap 'rm -f "$DAYTONA_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/daytona-latest/daytona.js" -o "$DAYTONA_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/daytona-latest/daytona.js" -o "$DAYTONA_JS" \
|
||||
|| { printf '\033[0;31mFailed to download daytona.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$DAYTONA_JS" kilocode "$@"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled daytona.js from GitHub release
|
||||
DAYTONA_JS=$(mktemp)
|
||||
trap 'rm -f "$DAYTONA_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/daytona-latest/daytona.js" -o "$DAYTONA_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/daytona-latest/daytona.js" -o "$DAYTONA_JS" \
|
||||
|| { printf '\033[0;31mFailed to download daytona.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$DAYTONA_JS" openclaw "$@"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled daytona.js from GitHub release
|
||||
DAYTONA_JS=$(mktemp)
|
||||
trap 'rm -f "$DAYTONA_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/daytona-latest/daytona.js" -o "$DAYTONA_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/daytona-latest/daytona.js" -o "$DAYTONA_JS" \
|
||||
|| { printf '\033[0;31mFailed to download daytona.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$DAYTONA_JS" opencode "$@"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled daytona.js from GitHub release
|
||||
DAYTONA_JS=$(mktemp)
|
||||
trap 'rm -f "$DAYTONA_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/daytona-latest/daytona.js" -o "$DAYTONA_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/daytona-latest/daytona.js" -o "$DAYTONA_JS" \
|
||||
|| { printf '\033[0;31mFailed to download daytona.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$DAYTONA_JS" pi "$@"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled daytona.js from GitHub release
|
||||
DAYTONA_JS=$(mktemp)
|
||||
trap 'rm -f "$DAYTONA_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/daytona-latest/daytona.js" -o "$DAYTONA_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/daytona-latest/daytona.js" -o "$DAYTONA_JS" \
|
||||
|| { printf '\033[0;31mFailed to download daytona.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$DAYTONA_JS" t3code "$@"
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ fi
|
|||
# Remote — download bundled digitalocean.js from GitHub release
|
||||
DO_JS=$(mktemp)
|
||||
trap 'rm -f "$DO_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/digitalocean-latest/digitalocean.js" -o "$DO_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/digitalocean-latest/digitalocean.js" -o "$DO_JS" \
|
||||
|| { printf '\033[0;31mFailed to download digitalocean.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
_run_with_restart bun run "$DO_JS" "$_AGENT_NAME" "$@"
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ fi
|
|||
# Remote — download bundled digitalocean.js from GitHub release
|
||||
DO_JS=$(mktemp)
|
||||
trap 'rm -f "$DO_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/digitalocean-latest/digitalocean.js" -o "$DO_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/digitalocean-latest/digitalocean.js" -o "$DO_JS" \
|
||||
|| { printf '\033[0;31mFailed to download digitalocean.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
_run_with_restart bun run "$DO_JS" "$_AGENT_NAME" "$@"
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ fi
|
|||
# Remote — download bundled digitalocean.js from GitHub release
|
||||
DO_JS=$(mktemp)
|
||||
trap 'rm -f "$DO_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/digitalocean-latest/digitalocean.js" -o "$DO_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/digitalocean-latest/digitalocean.js" -o "$DO_JS" \
|
||||
|| { printf '\033[0;31mFailed to download digitalocean.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
_run_with_restart bun run "$DO_JS" "$_AGENT_NAME" "$@"
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ fi
|
|||
# Remote — download bundled digitalocean.js from GitHub release
|
||||
DO_JS=$(mktemp)
|
||||
trap 'rm -f "$DO_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/digitalocean-latest/digitalocean.js" -o "$DO_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/digitalocean-latest/digitalocean.js" -o "$DO_JS" \
|
||||
|| { printf '\033[0;31mFailed to download digitalocean.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
_run_with_restart bun run "$DO_JS" "$_AGENT_NAME" "$@"
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ fi
|
|||
# Remote — download bundled digitalocean.js from GitHub release
|
||||
DO_JS=$(mktemp)
|
||||
trap 'rm -f "$DO_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/digitalocean-latest/digitalocean.js" -o "$DO_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/digitalocean-latest/digitalocean.js" -o "$DO_JS" \
|
||||
|| { printf '\033[0;31mFailed to download digitalocean.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
_run_with_restart bun run "$DO_JS" "$_AGENT_NAME" "$@"
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ fi
|
|||
# Remote — download bundled digitalocean.js from GitHub release
|
||||
DO_JS=$(mktemp)
|
||||
trap 'rm -f "$DO_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/digitalocean-latest/digitalocean.js" -o "$DO_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/digitalocean-latest/digitalocean.js" -o "$DO_JS" \
|
||||
|| { printf '\033[0;31mFailed to download digitalocean.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
_run_with_restart bun run "$DO_JS" "$_AGENT_NAME" "$@"
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ fi
|
|||
# Remote — download bundled digitalocean.js from GitHub release
|
||||
DO_JS=$(mktemp)
|
||||
trap 'rm -f "$DO_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/digitalocean-latest/digitalocean.js" -o "$DO_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/digitalocean-latest/digitalocean.js" -o "$DO_JS" \
|
||||
|| { printf '\033[0;31mFailed to download digitalocean.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
_run_with_restart bun run "$DO_JS" "$_AGENT_NAME" "$@"
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ fi
|
|||
# Remote — download bundled digitalocean.js from GitHub release
|
||||
DO_JS=$(mktemp)
|
||||
trap 'rm -f "$DO_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/digitalocean-latest/digitalocean.js" -o "$DO_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/digitalocean-latest/digitalocean.js" -o "$DO_JS" \
|
||||
|| { printf '\033[0;31mFailed to download digitalocean.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
_run_with_restart bun run "$DO_JS" "$_AGENT_NAME" "$@"
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ fi
|
|||
# Remote — download bundled digitalocean.js from GitHub release
|
||||
DO_JS=$(mktemp)
|
||||
trap 'rm -f "$DO_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/digitalocean-latest/digitalocean.js" -o "$DO_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/digitalocean-latest/digitalocean.js" -o "$DO_JS" \
|
||||
|| { printf '\033[0;31mFailed to download digitalocean.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
_run_with_restart bun run "$DO_JS" "$_AGENT_NAME" "$@"
|
||||
|
|
|
|||
|
|
@ -21,6 +21,6 @@ fi
|
|||
# Remote — download and run compiled TypeScript bundle
|
||||
DO_JS=$(mktemp)
|
||||
trap 'rm -f "$DO_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/digitalocean-latest/digitalocean.js" -o "$DO_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/digitalocean-latest/digitalocean.js" -o "$DO_JS" \
|
||||
|| { printf '\033[0;31mFailed to download digitalocean.js\033[0m\n' >&2; exit 1; }
|
||||
exec bun run "$DO_JS" t3code "$@"
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ RUN OC_ARCH=$(uname -m) && \
|
|||
OC_OS=$(uname -s | tr A-Z a-z) && \
|
||||
mkdir -p /tmp/opencode-install /root/.opencode/bin && \
|
||||
curl --proto '=https' -fsSL -o /tmp/opencode-install/oc.tar.gz \
|
||||
"https://github.com/sst/opencode/releases/latest/download/opencode-${OC_OS}-${OC_ARCH}.tar.gz" && \
|
||||
"https://github.com/anomalyco/opencode/releases/latest/download/opencode-${OC_OS}-${OC_ARCH}.tar.gz" && \
|
||||
tar xzf /tmp/opencode-install/oc.tar.gz -C /tmp/opencode-install && \
|
||||
mv /tmp/opencode-install/opencode /root/.opencode/bin/ && \
|
||||
rm -rf /tmp/opencode-install
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ ${example}
|
|||
|
||||
local issue_url
|
||||
if issue_url=$(gh issue create \
|
||||
--repo OpenRouterTeam/spawn \
|
||||
--repo OpenRouterLabs/spawn \
|
||||
--title "${title}" \
|
||||
--label "ux" \
|
||||
--body "${body}" 2>/dev/null); then
|
||||
|
|
@ -80,7 +80,7 @@ ${example}
|
|||
else
|
||||
# Label may not exist — retry without it
|
||||
if issue_url=$(gh issue create \
|
||||
--repo OpenRouterTeam/spawn \
|
||||
--repo OpenRouterLabs/spawn \
|
||||
--title "${title}" \
|
||||
--body "${body}" 2>/dev/null); then
|
||||
log_ok "UX issue filed: ${issue_url}"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled gcp.js from GitHub release
|
||||
GCP_JS=$(mktemp)
|
||||
trap 'rm -f "$GCP_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/gcp-latest/gcp.js" -o "$GCP_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/gcp-latest/gcp.js" -o "$GCP_JS" \
|
||||
|| { printf '\033[0;31mFailed to download gcp.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$GCP_JS" claude "$@"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled gcp.js from GitHub release
|
||||
GCP_JS=$(mktemp)
|
||||
trap 'rm -f "$GCP_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/gcp-latest/gcp.js" -o "$GCP_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/gcp-latest/gcp.js" -o "$GCP_JS" \
|
||||
|| { printf '\033[0;31mFailed to download gcp.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$GCP_JS" codex "$@"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled gcp.js from GitHub release
|
||||
GCP_JS=$(mktemp)
|
||||
trap 'rm -f "$GCP_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/gcp-latest/gcp.js" -o "$GCP_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/gcp-latest/gcp.js" -o "$GCP_JS" \
|
||||
|| { printf '\033[0;31mFailed to download gcp.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$GCP_JS" cursor "$@"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled gcp.js from GitHub release
|
||||
GCP_JS=$(mktemp)
|
||||
trap 'rm -f "$GCP_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/gcp-latest/gcp.js" -o "$GCP_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/gcp-latest/gcp.js" -o "$GCP_JS" \
|
||||
|| { printf '\033[0;31mFailed to download gcp.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$GCP_JS" hermes "$@"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled gcp.js from GitHub release
|
||||
GCP_JS=$(mktemp)
|
||||
trap 'rm -f "$GCP_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/gcp-latest/gcp.js" -o "$GCP_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/gcp-latest/gcp.js" -o "$GCP_JS" \
|
||||
|| { printf '\033[0;31mFailed to download gcp.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$GCP_JS" junie "$@"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled gcp.js from GitHub release
|
||||
GCP_JS=$(mktemp)
|
||||
trap 'rm -f "$GCP_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/gcp-latest/gcp.js" -o "$GCP_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/gcp-latest/gcp.js" -o "$GCP_JS" \
|
||||
|| { printf '\033[0;31mFailed to download gcp.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$GCP_JS" kilocode "$@"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled gcp.js from GitHub release
|
||||
GCP_JS=$(mktemp)
|
||||
trap 'rm -f "$GCP_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/gcp-latest/gcp.js" -o "$GCP_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/gcp-latest/gcp.js" -o "$GCP_JS" \
|
||||
|| { printf '\033[0;31mFailed to download gcp.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$GCP_JS" openclaw "$@"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled gcp.js from GitHub release
|
||||
GCP_JS=$(mktemp)
|
||||
trap 'rm -f "$GCP_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/gcp-latest/gcp.js" -o "$GCP_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/gcp-latest/gcp.js" -o "$GCP_JS" \
|
||||
|| { printf '\033[0;31mFailed to download gcp.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$GCP_JS" opencode "$@"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled gcp.js from GitHub release
|
||||
GCP_JS=$(mktemp)
|
||||
trap 'rm -f "$GCP_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/gcp-latest/gcp.js" -o "$GCP_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/gcp-latest/gcp.js" -o "$GCP_JS" \
|
||||
|| { printf '\033[0;31mFailed to download gcp.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$GCP_JS" pi "$@"
|
||||
|
|
|
|||
|
|
@ -21,6 +21,6 @@ fi
|
|||
# Remote — download and run compiled TypeScript bundle
|
||||
GCP_JS=$(mktemp)
|
||||
trap 'rm -f "$GCP_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/gcp-latest/gcp.js" -o "$GCP_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/gcp-latest/gcp.js" -o "$GCP_JS" \
|
||||
|| { printf '\033[0;31mFailed to download gcp.js\033[0m\n' >&2; exit 1; }
|
||||
exec bun run "$GCP_JS" t3code "$@"
|
||||
|
|
|
|||
|
|
@ -17,6 +17,6 @@ fi
|
|||
|
||||
HETZNER_JS=$(mktemp)
|
||||
trap 'rm -f "$HETZNER_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/hetzner-latest/hetzner.js" -o "$HETZNER_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/hetzner-latest/hetzner.js" -o "$HETZNER_JS" \
|
||||
|| { printf '\033[0;31mFailed to download hetzner.js\033[0m\n' >&2; exit 1; }
|
||||
exec bun run "$HETZNER_JS" claude "$@"
|
||||
|
|
|
|||
|
|
@ -17,6 +17,6 @@ fi
|
|||
|
||||
HETZNER_JS=$(mktemp)
|
||||
trap 'rm -f "$HETZNER_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/hetzner-latest/hetzner.js" -o "$HETZNER_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/hetzner-latest/hetzner.js" -o "$HETZNER_JS" \
|
||||
|| { printf '\033[0;31mFailed to download hetzner.js\033[0m\n' >&2; exit 1; }
|
||||
exec bun run "$HETZNER_JS" codex "$@"
|
||||
|
|
|
|||
|
|
@ -21,6 +21,6 @@ fi
|
|||
# Remote — download and run compiled TypeScript bundle
|
||||
HETZNER_JS=$(mktemp)
|
||||
trap 'rm -f "$HETZNER_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/hetzner-latest/hetzner.js" -o "$HETZNER_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/hetzner-latest/hetzner.js" -o "$HETZNER_JS" \
|
||||
|| { printf '\033[0;31mFailed to download hetzner.js\033[0m\n' >&2; exit 1; }
|
||||
exec bun run "$HETZNER_JS" cursor "$@"
|
||||
|
|
|
|||
|
|
@ -21,6 +21,6 @@ fi
|
|||
# Remote — download and run compiled TypeScript bundle
|
||||
HETZNER_JS=$(mktemp)
|
||||
trap 'rm -f "$HETZNER_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/hetzner-latest/hetzner.js" -o "$HETZNER_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/hetzner-latest/hetzner.js" -o "$HETZNER_JS" \
|
||||
|| { printf '\033[0;31mFailed to download hetzner.js\033[0m\n' >&2; exit 1; }
|
||||
exec bun run "$HETZNER_JS" hermes "$@"
|
||||
|
|
|
|||
|
|
@ -21,6 +21,6 @@ fi
|
|||
# Remote — download and run compiled TypeScript bundle
|
||||
HETZNER_JS=$(mktemp)
|
||||
trap 'rm -f "$HETZNER_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/hetzner-latest/hetzner.js" -o "$HETZNER_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/hetzner-latest/hetzner.js" -o "$HETZNER_JS" \
|
||||
|| { printf '\033[0;31mFailed to download hetzner.js\033[0m\n' >&2; exit 1; }
|
||||
exec bun run "$HETZNER_JS" junie "$@"
|
||||
|
|
|
|||
|
|
@ -17,6 +17,6 @@ fi
|
|||
|
||||
HETZNER_JS=$(mktemp)
|
||||
trap 'rm -f "$HETZNER_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/hetzner-latest/hetzner.js" -o "$HETZNER_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/hetzner-latest/hetzner.js" -o "$HETZNER_JS" \
|
||||
|| { printf '\033[0;31mFailed to download hetzner.js\033[0m\n' >&2; exit 1; }
|
||||
exec bun run "$HETZNER_JS" kilocode "$@"
|
||||
|
|
|
|||
|
|
@ -17,6 +17,6 @@ fi
|
|||
|
||||
HETZNER_JS=$(mktemp)
|
||||
trap 'rm -f "$HETZNER_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/hetzner-latest/hetzner.js" -o "$HETZNER_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/hetzner-latest/hetzner.js" -o "$HETZNER_JS" \
|
||||
|| { printf '\033[0;31mFailed to download hetzner.js\033[0m\n' >&2; exit 1; }
|
||||
exec bun run "$HETZNER_JS" openclaw "$@"
|
||||
|
|
|
|||
|
|
@ -17,6 +17,6 @@ fi
|
|||
|
||||
HETZNER_JS=$(mktemp)
|
||||
trap 'rm -f "$HETZNER_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/hetzner-latest/hetzner.js" -o "$HETZNER_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/hetzner-latest/hetzner.js" -o "$HETZNER_JS" \
|
||||
|| { printf '\033[0;31mFailed to download hetzner.js\033[0m\n' >&2; exit 1; }
|
||||
exec bun run "$HETZNER_JS" opencode "$@"
|
||||
|
|
|
|||
|
|
@ -17,6 +17,6 @@ fi
|
|||
|
||||
HETZNER_JS=$(mktemp)
|
||||
trap 'rm -f "$HETZNER_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/hetzner-latest/hetzner.js" -o "$HETZNER_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/hetzner-latest/hetzner.js" -o "$HETZNER_JS" \
|
||||
|| { printf '\033[0;31mFailed to download hetzner.js\033[0m\n' >&2; exit 1; }
|
||||
exec bun run "$HETZNER_JS" pi "$@"
|
||||
|
|
|
|||
|
|
@ -21,6 +21,6 @@ fi
|
|||
# Remote — download and run compiled TypeScript bundle
|
||||
HETZNER_JS=$(mktemp)
|
||||
trap 'rm -f "$HETZNER_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/hetzner-latest/hetzner.js" -o "$HETZNER_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/hetzner-latest/hetzner.js" -o "$HETZNER_JS" \
|
||||
|| { printf '\033[0;31mFailed to download hetzner.js\033[0m\n' >&2; exit 1; }
|
||||
exec bun run "$HETZNER_JS" t3code "$@"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ Run agents directly on your local machine without any cloud provisioning.
|
|||
|
||||
## Quick Start
|
||||
|
||||
If you have the [spawn CLI](https://github.com/OpenRouterTeam/spawn) installed:
|
||||
If you have the [spawn CLI](https://github.com/OpenRouterLabs/spawn) installed:
|
||||
|
||||
```bash
|
||||
spawn claude local
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled local.js from GitHub release
|
||||
LOCAL_JS=$(mktemp)
|
||||
trap 'rm -f "$LOCAL_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/local-latest/local.js" -o "$LOCAL_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/local-latest/local.js" -o "$LOCAL_JS" \
|
||||
|| { printf '\033[0;31mFailed to download local.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$LOCAL_JS" claude "$@"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled local.js from GitHub release
|
||||
LOCAL_JS=$(mktemp)
|
||||
trap 'rm -f "$LOCAL_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/local-latest/local.js" -o "$LOCAL_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/local-latest/local.js" -o "$LOCAL_JS" \
|
||||
|| { printf '\033[0;31mFailed to download local.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$LOCAL_JS" codex "$@"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled local.js from GitHub release
|
||||
LOCAL_JS=$(mktemp)
|
||||
trap 'rm -f "$LOCAL_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/local-latest/local.js" -o "$LOCAL_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/local-latest/local.js" -o "$LOCAL_JS" \
|
||||
|| { printf '\033[0;31mFailed to download local.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$LOCAL_JS" cursor "$@"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled local.js from GitHub release
|
||||
LOCAL_JS=$(mktemp)
|
||||
trap 'rm -f "$LOCAL_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/local-latest/local.js" -o "$LOCAL_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/local-latest/local.js" -o "$LOCAL_JS" \
|
||||
|| { printf '\033[0;31mFailed to download local.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$LOCAL_JS" hermes "$@"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled local.js from GitHub release
|
||||
LOCAL_JS=$(mktemp)
|
||||
trap 'rm -f "$LOCAL_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/local-latest/local.js" -o "$LOCAL_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/local-latest/local.js" -o "$LOCAL_JS" \
|
||||
|| { printf '\033[0;31mFailed to download local.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$LOCAL_JS" junie "$@"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled local.js from GitHub release
|
||||
LOCAL_JS=$(mktemp)
|
||||
trap 'rm -f "$LOCAL_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/local-latest/local.js" -o "$LOCAL_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/local-latest/local.js" -o "$LOCAL_JS" \
|
||||
|| { printf '\033[0;31mFailed to download local.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$LOCAL_JS" kilocode "$@"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled local.js from GitHub release
|
||||
LOCAL_JS=$(mktemp)
|
||||
trap 'rm -f "$LOCAL_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/local-latest/local.js" -o "$LOCAL_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/local-latest/local.js" -o "$LOCAL_JS" \
|
||||
|| { printf '\033[0;31mFailed to download local.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$LOCAL_JS" openclaw "$@"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled local.js from GitHub release
|
||||
LOCAL_JS=$(mktemp)
|
||||
trap 'rm -f "$LOCAL_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/local-latest/local.js" -o "$LOCAL_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/local-latest/local.js" -o "$LOCAL_JS" \
|
||||
|| { printf '\033[0;31mFailed to download local.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$LOCAL_JS" opencode "$@"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled local.js from GitHub release
|
||||
LOCAL_JS=$(mktemp)
|
||||
trap 'rm -f "$LOCAL_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/local-latest/local.js" -o "$LOCAL_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/local-latest/local.js" -o "$LOCAL_JS" \
|
||||
|| { printf '\033[0;31mFailed to download local.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$LOCAL_JS" pi "$@"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fi
|
|||
# Remote — download bundled local.js from GitHub release
|
||||
LOCAL_JS=$(mktemp)
|
||||
trap 'rm -f "$LOCAL_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/local-latest/local.js" -o "$LOCAL_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/local-latest/local.js" -o "$LOCAL_JS" \
|
||||
|| { printf '\033[0;31mFailed to download local.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$LOCAL_JS" t3code "$@"
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ This was previously the `--beta sandbox` flag on the `local` cloud. It is now a
|
|||
|
||||
## Quick Start
|
||||
|
||||
If you have the [spawn CLI](https://github.com/OpenRouterTeam/spawn) installed:
|
||||
If you have the [spawn CLI](https://github.com/OpenRouterLabs/spawn) installed:
|
||||
|
||||
```bash
|
||||
spawn claude sandbox
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ fi
|
|||
# Remote — download bundled sandbox.js from GitHub release
|
||||
SANDBOX_JS=$(mktemp)
|
||||
trap 'rm -f "$SANDBOX_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/sandbox-latest/sandbox.js" -o "$SANDBOX_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/sandbox-latest/sandbox.js" -o "$SANDBOX_JS" \
|
||||
|| { printf '\033[0;31mFailed to download sandbox.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$SANDBOX_JS" claude "$@"
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ fi
|
|||
# Remote — download bundled sandbox.js from GitHub release
|
||||
SANDBOX_JS=$(mktemp)
|
||||
trap 'rm -f "$SANDBOX_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/sandbox-latest/sandbox.js" -o "$SANDBOX_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/sandbox-latest/sandbox.js" -o "$SANDBOX_JS" \
|
||||
|| { printf '\033[0;31mFailed to download sandbox.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$SANDBOX_JS" codex "$@"
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ fi
|
|||
# Remote — download bundled sandbox.js from GitHub release
|
||||
SANDBOX_JS=$(mktemp)
|
||||
trap 'rm -f "$SANDBOX_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/sandbox-latest/sandbox.js" -o "$SANDBOX_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/sandbox-latest/sandbox.js" -o "$SANDBOX_JS" \
|
||||
|| { printf '\033[0;31mFailed to download sandbox.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$SANDBOX_JS" cursor "$@"
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ fi
|
|||
# Remote — download bundled sandbox.js from GitHub release
|
||||
SANDBOX_JS=$(mktemp)
|
||||
trap 'rm -f "$SANDBOX_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/sandbox-latest/sandbox.js" -o "$SANDBOX_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/sandbox-latest/sandbox.js" -o "$SANDBOX_JS" \
|
||||
|| { printf '\033[0;31mFailed to download sandbox.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$SANDBOX_JS" hermes "$@"
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ fi
|
|||
# Remote — download bundled sandbox.js from GitHub release
|
||||
SANDBOX_JS=$(mktemp)
|
||||
trap 'rm -f "$SANDBOX_JS"' EXIT
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterTeam/spawn/releases/download/sandbox-latest/sandbox.js" -o "$SANDBOX_JS" \
|
||||
curl -fsSL --proto '=https' "https://github.com/OpenRouterLabs/spawn/releases/download/sandbox-latest/sandbox.js" -o "$SANDBOX_JS" \
|
||||
|| { printf '\033[0;31mFailed to download sandbox.js\033[0m\n' >&2; exit 1; }
|
||||
|
||||
exec bun run "$SANDBOX_JS" junie "$@"
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue