Compare commits

...

1 Commits

Author SHA1 Message Date
Jiayuan Zhang
606a515f91 refactor(cli): separate install from setup, redesign CLI configuration flow
Decouple install.sh from environment configuration — install.sh now only
installs the CLI binary (and optionally Docker via --with-server), while
all environment configuration moves to `multica setup` subcommands.

Key changes:
- install.sh: remove config writes, rename --local to --with-server
- multica setup: add cloud/self-host subcommands with --server-url,
  --app-url, --port, --frontend-port flags and --profile support
- Add config overwrite protection with interactive prompt
- Remove redundant commands: `config local`, `auth login` alias
- Replace silent multica.ai fallbacks with explicit errors
- Onboarding wizard: dynamically show correct setup command for
  Cloud vs Self-host environments
- Update all docs, landing page, and install scripts for consistency
2026-04-13 22:26:28 +08:00
23 changed files with 379 additions and 357 deletions

View File

@@ -35,7 +35,7 @@ This auto-detects your installation method (Homebrew or manual) and upgrades acc
multica setup
# For self-hosted (local) deployments:
multica setup --local
multica setup self-host
```
Or step by step:
@@ -184,23 +184,23 @@ Agent-specific overrides:
When connecting to a self-hosted Multica instance, the easiest approach is:
```bash
# One command — auto-detects local server, configures, authenticates, starts daemon
multica setup --local
# One command — configures for localhost, authenticates, starts daemon
multica setup self-host
# Or for on-premise with custom domains:
multica setup self-host --server-url https://api.example.com --app-url https://app.example.com
```
Or configure manually:
```bash
# Configure for local Docker Compose (default ports)
multica config local
# Or set URLs individually:
# multica config set app_url http://localhost:3000
# multica config set server_url http://localhost:8080
# Set URLs individually
multica config set server_url http://localhost:8080
multica config set app_url http://localhost:3000
# For production with TLS:
# multica config set app_url https://app.example.com
# multica config set server_url https://api.example.com
# multica config set app_url https://app.example.com
multica login
multica daemon start
@@ -211,9 +211,11 @@ multica daemon start
Profiles let you run multiple daemons on the same machine — for example, one for production and one for a staging server.
```bash
# Start a daemon for the staging server
multica --profile staging login
multica --profile staging daemon start
# Set up a staging profile
multica setup self-host --profile staging --server-url https://api-staging.example.com --app-url https://staging.example.com
# Start its daemon
multica daemon start --profile staging
# Default profile runs separately
multica daemon start
@@ -336,17 +338,20 @@ The `runs` command shows all past and current executions for an issue, including
## Setup
```bash
# One-command setup: configure, authenticate, and start the daemon
# One-command setup for Multica Cloud: configure, authenticate, and start the daemon
multica setup
# For local self-hosted deployments (auto-detects or forces local mode)
multica setup --local
# For local self-hosted deployments
multica setup self-host
# Custom ports
multica setup --local --port 9090 --frontend-port 4000
multica setup self-host --port 9090 --frontend-port 4000
# On-premise with custom domains
multica setup self-host --server-url https://api.example.com --app-url https://app.example.com
```
`multica setup` detects whether a local Multica server is running, configures the CLI, opens your browser for authentication, and starts the daemon — all in one step.
`multica setup` configures the CLI, opens your browser for authentication, and starts the daemon — all in one step. Use `multica setup self-host` to connect to a self-hosted server instead of Multica Cloud.
## Configuration
@@ -358,15 +363,6 @@ multica config show
Shows config file path, server URL, app URL, and default workspace.
### Configure for Local Self-Hosted
```bash
multica config local # Uses default ports (8080/3000)
multica config local --port 9090 --frontend-port 4000 # Custom ports
```
Sets `server_url` and `app_url` for a local Docker Compose deployment in one command.
### Set Values
```bash

View File

@@ -70,7 +70,7 @@ selfhost:
echo ""; \
echo "Next — install the CLI and connect your machine:"; \
echo " brew install multica-ai/tap/multica"; \
echo " multica setup --local"; \
echo " multica setup self-host"; \
else \
echo ""; \
echo "Services are still starting. Check logs:"; \

View File

@@ -62,18 +62,17 @@ Installs the Multica CLI on macOS and Linux. Works with Homebrew or downloads th
irm https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.ps1 | iex
```
After installation:
Then configure, authenticate, and start the daemon in one command:
```bash
multica login # Authenticate (opens browser)
multica daemon start # Start the local agent runtime
multica daemon stop # Stop the daemon when done
multica setup # Connect to Multica Cloud, log in, start daemon
```
> **Self-hosting?** Add `--local` to deploy a full Multica server on your machine:
> **Self-hosting?** Add `--with-server` to deploy a full Multica server on your machine:
>
> ```bash
> curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash -s -- --local
> curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash -s -- --with-server
> multica setup self-host
> ```
>
> Requires Docker. See the [Self-Hosting Guide](SELF_HOSTING.md) for details.
@@ -82,11 +81,10 @@ multica daemon stop # Stop the daemon when done
## Getting Started
### 1. Log in and start the daemon
### 1. Set up and start the daemon
```bash
multica login # Authenticate with your Multica account
multica daemon start # Start the local agent runtime
multica setup # Configure, authenticate, and start the daemon
```
The daemon runs in the background and auto-detects agent CLIs (`claude`, `codex`, `openclaw`, `opencode`) on your PATH.
@@ -116,9 +114,8 @@ The `multica` CLI connects your local machine to Multica — authenticate, manag
| `multica login` | Authenticate (opens browser) |
| `multica daemon start` | Start the local agent runtime |
| `multica daemon status` | Check daemon status |
| `multica setup` | One-command setup (configure + login + start daemon) |
| `multica setup --local` | Same, but for self-hosted deployments |
| `multica config local` | Configure CLI for a local self-hosted server |
| `multica setup` | One-command setup for Multica Cloud (configure + login + start daemon) |
| `multica setup self-host` | Same, but for self-hosted deployments |
| `multica issue list` | List issues in your workspace |
| `multica issue create` | Create a new issue |
| `multica update` | Update to the latest version |

View File

@@ -62,18 +62,17 @@ curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/ins
irm https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.ps1 | iex
```
安装完成后:
安装完成后,一条命令完成配置、认证和启动
```bash
multica login # 认证(打开浏览器)
multica daemon start # 启动本地 Agent 运行时
multica daemon stop # 停止 daemon
multica setup # 连接 Multica Cloud登录启动 daemon
```
> **自部署?** 加上 `--local` 在本地部署完整的 Multica 服务:
> **自部署?** 加上 `--with-server` 在本地部署完整的 Multica 服务:
>
> ```bash
> curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash -s -- --local
> curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash -s -- --with-server
> multica setup self-host
> ```
>
> 需要 Docker。详见 [自部署指南](SELF_HOSTING.md)。
@@ -84,11 +83,10 @@ multica daemon stop # 停止 daemon
安装好 CLI或注册 [Multica 云服务](https://multica.ai))后,按以下步骤将第一个任务分配给 Agent
### 1. 登录并启动 daemon
### 1. 配置并启动 daemon
```bash
multica login # 使用你的 Multica 账号认证
multica daemon start # 启动本地 Agent 运行时
multica setup # 配置、认证、启动 daemon一条命令搞定
```
daemon 在后台运行,保持你的机器与 Multica 的连接。它会自动检测 PATH 中可用的 Agent CLI`claude``codex``openclaw``opencode`)。

View File

@@ -14,20 +14,19 @@ Each user who runs AI agents locally also installs the **`multica` CLI** and run
## Quick Install (Recommended)
One command to set up everything — server, CLI, and configuration:
Two commands to set up everything — server, CLI, and configuration:
```bash
curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash -s -- --local
# 1. Install CLI + provision the self-host server
curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash -s -- --with-server
# 2. Configure CLI, authenticate, and start the daemon
multica setup self-host
```
This automatically clones the repository, starts all services via Docker Compose, and installs the `multica` CLI.
This clones the repository, starts all services via Docker Compose, installs the `multica` CLI, then configures it for localhost.
Once complete, open http://localhost:3000, log in with any email + verification code **`888888`**, then:
```bash
multica login # Authenticate (opens browser)
multica daemon start # Start the agent daemon
```
Open http://localhost:3000, log in with any email + verification code **`888888`**.
> **Prerequisites:** Docker and Docker Compose must be installed. The script checks for this and provides install links if missing.
@@ -85,7 +84,7 @@ You also need at least one AI agent CLI installed:
### b) One-command setup
```bash
multica setup --local
multica setup self-host
```
This automatically:
@@ -94,6 +93,12 @@ This automatically:
3. Discovers your workspaces
4. Starts the daemon in the background
For on-premise deployments with custom domains:
```bash
multica setup self-host --server-url https://api.example.com --app-url https://app.example.com
```
To verify the daemon is running:
```bash
@@ -132,16 +137,10 @@ multica daemon stop
If you've been self-hosting and want to switch your CLI to [Multica Cloud](https://multica.ai):
```bash
multica config set server_url https://api.multica.ai
multica config set app_url https://multica.ai
multica login
multica setup
```
Or re-run the install script without `--local` — it will reconfigure the CLI automatically:
```bash
curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash
```
This reconfigures the CLI for multica.ai, re-authenticates, and restarts the daemon. You will be prompted before overwriting the existing configuration.
> Your local Docker services are unaffected. Stop them separately if you no longer need them.
@@ -184,11 +183,8 @@ If you prefer configuring the CLI step by step instead of `multica setup`:
```bash
# Point CLI to your local server
multica config local
# Or set URLs manually:
# multica config set app_url http://localhost:3000
# multica config set server_url http://localhost:8080
multica config set server_url http://localhost:8080
multica config set app_url http://localhost:3000
# Login (opens browser)
multica login

View File

@@ -8,15 +8,17 @@ This document is designed for AI agents to execute. Follow these steps exactly t
- Homebrew installed (for CLI)
- At least one AI agent CLI on PATH: `claude` or `codex`
## One-Command Install
## Install
```bash
curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash -s -- --local
# Install CLI + provision self-host server
curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash -s -- --with-server
# Configure CLI for localhost, authenticate, and start daemon
multica setup self-host
```
This installs everything: clones the repo, starts Docker services, and installs the CLI.
Wait for the output `✓ Multica is installed and running!` before proceeding.
Wait for the server output `✓ Multica server is running and CLI is ready!` before running `multica setup self-host`.
**Expected result:**
- Frontend at http://localhost:3000
@@ -30,10 +32,10 @@ git clone https://github.com/multica-ai/multica.git
cd multica
make selfhost
brew install multica-ai/tap/multica
multica setup --local
multica setup self-host
```
The `multica setup --local` command will:
The `multica setup self-host` command will:
1. Configure CLI to connect to localhost:8080 / localhost:3000
2. Open a browser for login — use verification code `888888` with any email
3. Discover workspaces automatically
@@ -64,7 +66,7 @@ If the default ports (8080/3000) are in use:
1. Edit `.env` and change `PORT` and `FRONTEND_PORT`
2. Run `make selfhost`
3. Run `multica setup --local --port <PORT> --frontend-port <FRONTEND_PORT>`
3. Run `multica setup self-host --port <PORT> --frontend-port <FRONTEND_PORT>`
## Troubleshooting

View File

@@ -57,16 +57,13 @@ This auto-detects your installation method (Homebrew or manual) and upgrades acc
## Quick Start
```bash
# 1. Authenticate (opens browser for login)
multica login
# 2. Start the agent daemon
multica daemon start
# 3. Done — agents in your watched workspaces can now execute tasks on your machine
# One command: configure, authenticate, and start the daemon
multica setup
```
`multica login` automatically discovers all workspaces you belong to and adds them to the daemon watch list.
This configures the CLI for Multica Cloud, opens your browser for login, discovers your workspaces, and starts the agent daemon.
For self-hosted servers, use `multica setup self-host` instead. See [Self-Hosting](/docs/getting-started/self-hosting) for details.
## Verify

View File

@@ -156,9 +156,11 @@ multica config set server_url wss://api.example.com/ws
Profiles let you run multiple daemons on the same machine — for example, one for production and one for a staging server.
```bash
# Start a daemon for the staging server
multica --profile staging login
multica --profile staging daemon start
# Set up a staging profile
multica setup self-host --profile staging --server-url https://api-staging.example.com --app-url https://staging.example.com
# Start its daemon
multica daemon start --profile staging
# Default profile runs separately
multica daemon start

View File

@@ -20,13 +20,11 @@ Fetch https://github.com/multica-ai/multica/blob/main/CLI_INSTALL.md and follow
Or install manually:
```bash
# Install
brew tap multica-ai/tap
brew install multica
# Install the CLI
curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash
# Authenticate and start
multica login
multica daemon start
# Configure, authenticate, and start the daemon
multica setup
```
The daemon auto-detects available agent CLIs (`claude`, `codex`, `openclaw`, `opencode`) on your PATH. When an agent is assigned a task, the daemon creates an isolated environment, runs the agent, and reports results back.

View File

@@ -21,16 +21,17 @@ Each user who wants to run AI agents locally also installs the **`multica` CLI**
## Quick Install
One command to set up everything:
Two commands to set up everything:
```bash
curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash -s -- --local
# Install CLI + provision self-host server
curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash -s -- --with-server
# Configure CLI, authenticate, and start the daemon
multica setup self-host
```
This clones the repo, starts all services, installs the CLI, and configures everything. Then:
1. Open http://localhost:3000 — log in with any email + code **`888888`**
2. Run `multica login` and `multica daemon start`
This clones the repo, starts all services, installs the CLI, and configures it for localhost. Then open http://localhost:3000 — log in with any email + code **`888888`**.
<Callout>
For a step-by-step setup, see below.
@@ -86,7 +87,7 @@ You also need at least one AI agent CLI:
### b) One-command setup
```bash
multica setup --local
multica setup self-host
```
This automatically:
@@ -95,6 +96,12 @@ This automatically:
3. Discovers your workspaces
4. Starts the daemon in the background
For on-premise deployments with custom domains:
```bash
multica setup self-host --server-url https://api.example.com --app-url https://app.example.com
```
Verify the daemon is running:
```bash
@@ -102,7 +109,7 @@ multica daemon status
```
<Callout>
Alternatively, configure manually: `multica config local && multica login && multica daemon start`
Alternatively, configure step by step: `multica config set server_url http://localhost:8080 && multica config set app_url http://localhost:3000 && multica login && multica daemon start`
</Callout>
### Step 4 — Verify & Start Using
@@ -127,16 +134,10 @@ multica daemon stop
If you've been self-hosting and want to switch your CLI to [Multica Cloud](https://multica.ai):
```bash
multica config set server_url https://api.multica.ai
multica config set app_url https://multica.ai
multica login
multica setup
```
Or re-run the install script without `--local` — it will reconfigure the CLI automatically:
```bash
curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash
```
This reconfigures the CLI for multica.ai, re-authenticates, and restarts the daemon. You will be prompted before overwriting the existing configuration.
<Callout>
Your local Docker services are unaffected. Stop them separately if you no longer need them.

View File

@@ -5,14 +5,13 @@ description: Assign your first task to an agent in under 5 minutes.
Once you have the CLI installed (or signed up for [Multica Cloud](https://multica.ai)), follow these steps to assign your first task to an agent.
## 1. Log in and start the daemon
## 1. Set up and start the daemon
```bash
multica login # Authenticate with your Multica account
multica daemon start # Start the local agent runtime
multica setup # Configure, authenticate, and start the daemon
```
The daemon runs in the background and keeps your machine connected to Multica. It auto-detects agent CLIs (`claude`, `codex`, `openclaw`, `opencode`) available on your PATH.
This configures the CLI, opens your browser for login, discovers your workspaces, and starts the agent daemon in the background. It auto-detects agent CLIs (`claude`, `codex`, `openclaw`, `opencode`) available on your PATH.
## 2. Verify your runtime

View File

@@ -126,7 +126,7 @@ export const en: LandingDict = {
{
title: "Install the CLI & connect your machine",
description:
"Run multica login to authenticate, then multica daemon start. The daemon auto-detects Claude Code, Codex, OpenClaw, and OpenCode on your machine \u2014 plug in and go.",
"Run multica setup to configure, authenticate, and start the daemon. It auto-detects Claude Code, Codex, OpenClaw, and OpenCode on your machine \u2014 plug in and go.",
},
{
title: "Create your first agent",
@@ -301,7 +301,7 @@ export const en: LandingDict = {
title: "One-Click Setup, Self-Hosting & Stability",
changes: [],
features: [
"One-click install & setup — `curl | bash` installs CLI, `--local` bootstraps full self-hosting, `multica setup` auto-detects local server",
"One-click install & setup — `curl | bash` installs CLI, `--with-server` bootstraps full self-hosting, `multica setup` configures your environment",
"Self-hosted storage — local file fallback when S3 is unavailable, plus custom S3 endpoint support (MinIO)",
"Inline property editing (priority, status, lead) on project list page",
],

View File

@@ -126,7 +126,7 @@ export const zh: LandingDict = {
{
title: "\u5b89\u88c5 CLI \u5e76\u8fde\u63a5\u4f60\u7684\u673a\u5668",
description:
"\u8fd0\u884c multica login \u8fdb\u884c\u8ba4\u8bc1\uff0c\u7136\u540e multica daemon start\u3002\u5b88\u62a4\u8fdb\u7a0b\u81ea\u52a8\u68c0\u6d4b\u4f60\u673a\u5668\u4e0a\u7684 Claude Code\u3001Codex\u3001OpenClaw \u548c OpenCode\u2014\u2014\u63d2\u4e0a\u5c31\u7528\u3002",
"运行 multica setup 一键完成配置、认证和启动。守护进程自动检测你机器上的 Claude Code、Codex、OpenClaw OpenCode——插上就用。",
},
{
title: "\u521b\u5efa\u4f60\u7684\u7b2c\u4e00\u4e2a Agent",
@@ -301,7 +301,7 @@ export const zh: LandingDict = {
title: "一键安装、自部署与稳定性",
changes: [],
features: [
"一键安装与配置——`curl | bash` 安装 CLI`--local` 完整自部署,`multica setup` 自动检测本地服务器",
"一键安装与配置——`curl | bash` 安装 CLI`--with-server` 完整自部署,`multica setup` 配置连接环境",
"自部署存储——无 S3 时本地文件存储回退,支持自定义 S3 端点MinIO",
"项目列表页支持行内编辑属性(优先级、状态、负责人)",
],

View File

@@ -77,6 +77,10 @@ export class ApiClient {
this.logger = options?.logger ?? noopLogger;
}
getBaseUrl(): string {
return this.baseUrl;
}
setToken(token: string | null) {
this.token = token;
}

View File

@@ -1,27 +1,49 @@
"use client";
import { useState, useCallback } from "react";
import { useState, useCallback, useMemo } from "react";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { Check, Copy, Terminal, Loader2 } from "lucide-react";
import { Button } from "@multica/ui/components/ui/button";
import { Card, CardContent } from "@multica/ui/components/ui/card";
import { useWSEvent } from "@multica/core/realtime";
import { api } from "@multica/core/api";
import { ProviderLogo } from "../runtimes/components/provider-logo";
import {
runtimeListOptions,
runtimeKeys,
} from "@multica/core/runtimes/queries";
const SETUP_STEPS = [
{
label: "Install the Multica CLI",
cmd: "curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash",
},
{
label: "Set up and start the daemon",
cmd: "multica setup",
},
];
const CLOUD_HOST = "multica.ai";
const INSTALL_STEP = {
label: "Install the Multica CLI",
cmd: "curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash",
};
function isCloudEnvironment(): boolean {
if (typeof window === "undefined") return true;
return window.location.hostname.endsWith(CLOUD_HOST);
}
function buildSetupCommand(): string {
if (isCloudEnvironment()) return "multica setup";
const appUrl = typeof window !== "undefined" ? window.location.origin : "";
const apiBaseUrl = api.getBaseUrl?.() ?? "";
const serverUrl = apiBaseUrl || appUrl;
if (!serverUrl || serverUrl === "http://localhost:8080") {
// Default self-host — no flags needed
return "multica setup self-host";
}
const parts = ["multica setup self-host"];
parts.push(`--server-url ${serverUrl}`);
if (appUrl && appUrl !== serverUrl) {
parts.push(`--app-url ${appUrl}`);
}
return parts.join(" ");
}
function CopyButton({ text }: { text: string }) {
const [copied, setCopied] = useState(false);
@@ -56,6 +78,14 @@ export function StepRuntime({
}) {
const qc = useQueryClient();
const setupSteps = useMemo(
() => [
INSTALL_STEP,
{ label: "Set up and start the daemon", cmd: buildSetupCommand() },
],
[],
);
const { data: runtimes = [] } = useQuery(runtimeListOptions(wsId));
const handleDaemonEvent = useCallback(() => {
@@ -73,19 +103,16 @@ export function StepRuntime({
Connect a Runtime
</h1>
<p className="mt-2 text-muted-foreground">
Install the CLI and run{" "}
<code className="rounded bg-muted px-1.5 py-0.5 font-mono text-sm">
multica setup
</code>{" "}
to connect your machine. The daemon auto-detects agent CLIs (Claude
Code, Codex, etc.) on your PATH.
Install the CLI and run the setup command below to connect your
machine. The daemon auto-detects agent CLIs (Claude Code, Codex,
etc.) on your PATH.
</p>
</div>
{/* Commands */}
<Card className="w-full">
<CardContent className="space-y-3 pt-4">
{SETUP_STEPS.map((step, i) => (
{setupSteps.map((step, i) => (
<div key={i}>
<p className="mb-1.5 text-xs text-muted-foreground">
{i + 1}. {step.label}
@@ -100,11 +127,8 @@ export function StepRuntime({
</div>
))}
<p className="pt-1 text-xs text-muted-foreground">
<code className="rounded bg-background px-1 py-0.5 font-mono">
multica setup
</code>{" "}
handles authentication, configuration, and daemon startup. It
auto-detects local servers on your network.
The setup command handles authentication, configuration, and daemon
startup all in one step.
</p>
</CardContent>
</Card>

View File

@@ -273,26 +273,6 @@ function Install-Server {
Pop-Location
}
# ---------------------------------------------------------------------------
# Configure CLI
# ---------------------------------------------------------------------------
function Set-ConfigLocal {
Write-Info "Configuring CLI for local server..."
try {
multica config local 2>$null
} catch {
multica config set app_url http://localhost:3000 2>$null
multica config set server_url http://localhost:8080 2>$null
}
Write-Ok "CLI configured for localhost (backend :8080, frontend :3000)"
}
function Set-ConfigCloud {
Write-Info "Configuring CLI for Multica Cloud..."
multica config set server_url https://api.multica.ai 2>$null
multica config set app_url https://multica.ai 2>$null
Write-Ok "CLI configured for multica.ai"
}
# ---------------------------------------------------------------------------
# Main: Default mode (cloud)
@@ -300,28 +280,22 @@ function Set-ConfigCloud {
function Start-DefaultInstall {
Write-Host ""
Write-Host " Multica - Installer" -ForegroundColor White
Write-Host " Installing the CLI to connect to multica.ai" -ForegroundColor Cyan
Write-Host ""
Install-Cli
Set-ConfigCloud
Write-Host ""
Write-Host " ============================================" -ForegroundColor Green
Write-Host " [OK] Multica CLI is installed!" -ForegroundColor Green
Write-Host " [OK] Multica CLI is ready!" -ForegroundColor Green
Write-Host " ============================================" -ForegroundColor Green
Write-Host ""
Write-Host " Next steps:"
Write-Host " Next: configure your environment"
Write-Host ""
Write-Host " multica login " -NoNewline; Write-Host "# Authenticate with multica.ai" -ForegroundColor DarkGray
Write-Host " multica daemon start " -NoNewline; Write-Host "# Start the agent daemon" -ForegroundColor DarkGray
Write-Host " multica setup " -NoNewline; Write-Host "# Connect to Multica Cloud (multica.ai)" -ForegroundColor DarkGray
Write-Host " multica setup self-host " -NoNewline; Write-Host "# Connect to a self-hosted server" -ForegroundColor DarkGray
Write-Host ""
Write-Host " Or do it all in one command:"
Write-Host ""
Write-Host " multica setup" -ForegroundColor Cyan
Write-Host ""
Write-Host " Self-hosting? Re-run with:"
Write-Host ' $env:MULTICA_MODE="local"; irm https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.ps1 | iex'
Write-Host " Self-hosting? Install the server first:"
Write-Host ' $env:MULTICA_MODE="with-server"; irm https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.ps1 | iex'
Write-Host ""
}
@@ -331,30 +305,27 @@ function Start-DefaultInstall {
function Start-LocalInstall {
Write-Host ""
Write-Host " Multica - Self-Host Installer" -ForegroundColor White
Write-Host " Setting up a local Multica server + CLI"
Write-Host " Provisioning server infrastructure + installing CLI"
Write-Host ""
Test-Docker
Install-Server
Install-Cli
Set-ConfigLocal
Write-Host ""
Write-Host " ============================================" -ForegroundColor Green
Write-Host " [OK] Multica is installed and running!" -ForegroundColor Green
Write-Host " [OK] Multica server is running and CLI is ready!" -ForegroundColor Green
Write-Host " ============================================" -ForegroundColor Green
Write-Host ""
Write-Host " Frontend: http://localhost:3000"
Write-Host " Backend: http://localhost:8080"
Write-Host " Server at: $InstallDir"
Write-Host ""
Write-Host " Next steps:"
Write-Host " 1. Open http://localhost:3000 in your browser"
Write-Host " 2. Log in with any email + verification code: 888888"
Write-Host " 3. Then run:"
Write-Host " Next: configure your CLI to connect"
Write-Host ""
Write-Host " multica login " -NoNewline; Write-Host "# Authenticate (opens browser)" -ForegroundColor DarkGray
Write-Host " multica daemon start " -NoNewline; Write-Host "# Start the agent daemon" -ForegroundColor DarkGray
Write-Host " multica setup self-host " -NoNewline; Write-Host "# Configure + authenticate + start daemon" -ForegroundColor DarkGray
Write-Host ""
Write-Host " Default verification code: 888888"
Write-Host ""
Write-Host " To stop all services:"
Write-Host ' $env:MULTICA_MODE="stop"; irm https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.ps1 | iex'
@@ -397,7 +368,8 @@ function Start-Stop {
$mode = if ($env:MULTICA_MODE) { $env:MULTICA_MODE.ToLower() } else { "default" }
switch ($mode) {
"local" { Start-LocalInstall }
"stop" { Start-Stop }
default { Start-DefaultInstall }
"with-server" { Start-LocalInstall }
"local" { Start-LocalInstall } # backwards compat alias
"stop" { Start-Stop }
default { Start-DefaultInstall }
}

View File

@@ -1,11 +1,13 @@
#!/usr/bin/env bash
# Multica installer — one command to get started.
# Multica installer — installs the CLI and optionally provisions a self-host server.
#
# Install CLI (default): connects to multica.ai
# Install / upgrade CLI only:
# curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash
#
# Self-host: starts a local Multica server + installs CLI + configures
# curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash -s -- --local
# Install CLI + provision self-host server:
# curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash -s -- --with-server
#
# After installation, run `multica setup` to configure your environment.
#
set -euo pipefail
@@ -203,7 +205,7 @@ Install Docker:
macOS: https://docs.docker.com/desktop/install/mac-install/
Linux: https://docs.docker.com/engine/install/
After installing Docker, re-run this script with --local."
After installing Docker, re-run this script with --with-server."
fi
if ! docker info >/dev/null 2>&1; then
@@ -214,7 +216,7 @@ After installing Docker, re-run this script with --local."
}
# ---------------------------------------------------------------------------
# Server setup (self-host / --local)
# Server setup (self-host / --with-server)
# ---------------------------------------------------------------------------
setup_server() {
info "Setting up Multica server..."
@@ -281,100 +283,65 @@ setup_server() {
fi
}
# ---------------------------------------------------------------------------
# Configure CLI for local server
# ---------------------------------------------------------------------------
configure_local() {
info "Configuring CLI for local server..."
multica config local 2>/dev/null || {
# Fallback if config local doesn't exist in installed version
multica config set app_url http://localhost:3000 2>/dev/null || true
multica config set server_url http://localhost:8080 2>/dev/null || true
}
ok "CLI configured for localhost (backend :8080, frontend :3000)"
}
# ---------------------------------------------------------------------------
# Configure CLI for Multica Cloud
# ---------------------------------------------------------------------------
configure_cloud() {
info "Configuring CLI for Multica Cloud..."
multica config set server_url https://api.multica.ai 2>/dev/null || true
multica config set app_url https://multica.ai 2>/dev/null || true
ok "CLI configured for multica.ai"
}
# ---------------------------------------------------------------------------
# Main: Default mode (cloud — install CLI to connect to multica.ai)
# Main: Default mode (install / upgrade CLI only)
# ---------------------------------------------------------------------------
run_default() {
printf "\n"
printf "${BOLD} Multica — Installer${RESET}\n"
printf " Installing the CLI to connect to ${CYAN}multica.ai${RESET}\n"
printf "\n"
detect_os
install_cli
configure_cloud
printf "\n"
printf "${BOLD}${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}\n"
printf "${BOLD}${GREEN} ✓ Multica CLI is installed!${RESET}\n"
printf "${BOLD}${GREEN} ✓ Multica CLI is ready!${RESET}\n"
printf "${BOLD}${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}\n"
printf "\n"
printf " ${BOLD}Next steps:${RESET}\n"
printf " ${BOLD}Next: configure your environment${RESET}\n"
printf "\n"
printf " ${CYAN}multica login${RESET} # Authenticate with multica.ai\n"
printf " ${CYAN}multica daemon start${RESET} # Start the agent daemon\n"
printf " ${CYAN}multica setup${RESET} # Connect to Multica Cloud (multica.ai)\n"
printf " ${CYAN}multica setup self-host${RESET} # Connect to a self-hosted server\n"
printf "\n"
printf " Or do it all in one command:\n"
printf "\n"
printf " ${CYAN}multica setup${RESET}\n"
printf "\n"
printf " ${BOLD}Self-hosting?${RESET} Re-run with --local:\n"
printf " curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash -s -- --local\n"
printf " ${BOLD}Self-hosting?${RESET} Install the server first:\n"
printf " curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash -s -- --with-server\n"
printf "\n"
}
# ---------------------------------------------------------------------------
# Main: Local mode (self-host — full server + CLI)
# Main: With-server mode (provision self-host infrastructure + install CLI)
# ---------------------------------------------------------------------------
run_local() {
run_with_server() {
printf "\n"
printf "${BOLD} Multica — Self-Host Installer${RESET}\n"
printf " Setting up a local Multica server + CLI\n"
printf " Provisioning server infrastructure + installing CLI\n"
printf "\n"
detect_os
check_docker
setup_server
install_cli
configure_local
printf "\n"
printf "${BOLD}${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}\n"
printf "${BOLD}${GREEN} ✓ Multica is installed and running!${RESET}\n"
printf "${BOLD}${GREEN} ✓ Multica server is running and CLI is ready!${RESET}\n"
printf "${BOLD}${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}\n"
printf "\n"
printf " ${BOLD}Frontend:${RESET} http://localhost:3000\n"
printf " ${BOLD}Backend:${RESET} http://localhost:8080\n"
printf " ${BOLD}Server at:${RESET} %s\n" "$INSTALL_DIR"
printf "\n"
printf " ${BOLD}Next steps:${RESET}\n"
printf " 1. Open ${CYAN}http://localhost:3000${RESET} in your browser\n"
printf " 2. Log in with any email + verification code: ${BOLD}888888${RESET}\n"
printf " 3. Then run:\n"
printf " ${BOLD}Next: configure your CLI to connect${RESET}\n"
printf "\n"
printf " ${CYAN}multica login${RESET} # Authenticate (opens browser)\n"
printf " ${CYAN}multica daemon start${RESET} # Start the agent daemon\n"
printf " ${CYAN}multica setup self-host${RESET} # Configure + authenticate + start daemon\n"
printf "\n"
printf " Default verification code: ${BOLD}888888${RESET}\n"
printf "\n"
printf " ${BOLD}To stop all services:${RESET}\n"
printf " curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash -s -- --stop\n"
printf "\n"
printf " Or manually:\n"
printf " cd %s && docker compose -f docker-compose.selfhost.yml down\n" "$INSTALL_DIR"
printf " multica daemon stop\n"
printf "\n"
}
# ---------------------------------------------------------------------------
@@ -411,14 +378,17 @@ main() {
while [ $# -gt 0 ]; do
case "$1" in
--local) mode="local" ;;
--stop) mode="stop" ;;
--with-server) mode="with-server" ;;
--local) mode="with-server" ;; # backwards compat alias
--stop) mode="stop" ;;
--help|-h)
echo "Usage: install.sh [--local | --stop]"
echo "Usage: install.sh [--with-server | --stop]"
echo ""
echo " (default) Install the Multica CLI to connect to multica.ai"
echo " --local Self-host: set up a local Multica server + CLI"
echo " --stop Stop a self-hosted installation"
echo " (default) Install / upgrade the Multica CLI"
echo " --with-server Install CLI + provision a self-host server (Docker)"
echo " --stop Stop a self-hosted installation"
echo ""
echo "After installation, run 'multica setup' to configure your environment."
exit 0
;;
*) warn "Unknown option: $1" ;;
@@ -427,9 +397,9 @@ main() {
done
case "$mode" in
default) run_default ;;
local) run_local ;;
stop) run_stop ;;
default) run_default ;;
with-server) run_with_server ;;
stop) run_stop ;;
esac
}

View File

@@ -179,13 +179,12 @@ func resolveServerURL(cmd *cobra.Command) string {
}
profile := resolveProfile(cmd)
cfg, err := cli.LoadCLIConfigForProfile(profile)
if err != nil {
return "https://api.multica.ai"
}
if cfg.ServerURL != "" {
if err == nil && cfg.ServerURL != "" {
return normalizeAPIBaseURL(cfg.ServerURL)
}
return "https://api.multica.ai"
fmt.Fprintln(os.Stderr, "No server configured. Run 'multica setup' first.")
os.Exit(1)
return "" // unreachable
}
func normalizeAPIBaseURL(raw string) string {

View File

@@ -25,14 +25,6 @@ var authCmd = &cobra.Command{
Short: "Authenticate multica with Multica",
}
var authLoginCmd = &cobra.Command{
Use: "login",
Short: "Authenticate with Multica",
Long: "Authenticate with Multica without auto-configuring workspaces. Use 'multica login' for the guided setup flow.",
Hidden: true,
RunE: runAuthLogin,
}
var authStatusCmd = &cobra.Command{
Use: "status",
Short: "Show current authentication status",
@@ -46,8 +38,6 @@ var authLogoutCmd = &cobra.Command{
}
func init() {
authLoginCmd.Flags().Bool("token", false, "Authenticate by pasting a personal access token")
authCmd.AddCommand(authLoginCmd)
authCmd.AddCommand(authStatusCmd)
authCmd.AddCommand(authLogoutCmd)
}
@@ -72,7 +62,9 @@ func resolveAppURL(cmd *cobra.Command) string {
if err == nil && cfg.AppURL != "" {
return strings.TrimRight(cfg.AppURL, "/")
}
return "https://multica.ai"
fmt.Fprintln(os.Stderr, "No app URL configured. Run 'multica setup' first.")
os.Exit(1)
return "" // unreachable
}
func openBrowser(url string) error {

View File

@@ -34,16 +34,6 @@ func TestResolveAppURL(t *testing.T) {
t.Fatalf("resolveAppURL() = %q, want %q", got, "http://localhost:13026")
}
})
t.Run("defaults to production", func(t *testing.T) {
t.Setenv("MULTICA_APP_URL", "")
t.Setenv("FRONTEND_ORIGIN", "")
t.Setenv("HOME", t.TempDir()) // avoid reading real config
if got := resolveAppURL(cmd); got != "https://multica.ai" {
t.Fatalf("resolveAppURL() = %q, want %q", got, "https://multica.ai")
}
})
}
func TestNormalizeAPIBaseURL(t *testing.T) {

View File

@@ -7,12 +7,6 @@ import (
)
func TestLegacyCompatibilityCommandsRemainAvailable(t *testing.T) {
t.Run("auth login remains available", func(t *testing.T) {
if _, _, err := authCmd.Find([]string{"login"}); err != nil {
t.Fatalf("expected auth login command to exist: %v", err)
}
})
t.Run("workspace get remains available", func(t *testing.T) {
if _, _, err := workspaceCmd.Find([]string{"get"}); err != nil {
t.Fatalf("expected workspace get command to exist: %v", err)

View File

@@ -29,20 +29,9 @@ var configSetCmd = &cobra.Command{
RunE: runConfigSet,
}
var configLocalCmd = &cobra.Command{
Use: "local",
Short: "Configure CLI for a local Docker Compose deployment",
Long: "Sets server_url and app_url to localhost defaults for a local self-hosted deployment.",
RunE: runConfigLocal,
}
func init() {
configLocalCmd.Flags().Int("port", 8080, "Backend server port")
configLocalCmd.Flags().Int("frontend-port", 3000, "Frontend port")
configCmd.AddCommand(configShowCmd)
configCmd.AddCommand(configSetCmd)
configCmd.AddCommand(configLocalCmd)
}
func runConfigShow(cmd *cobra.Command, _ []string) error {
@@ -91,29 +80,6 @@ func runConfigSet(cmd *cobra.Command, args []string) error {
return nil
}
func runConfigLocal(cmd *cobra.Command, _ []string) error {
port, _ := cmd.Flags().GetInt("port")
frontendPort, _ := cmd.Flags().GetInt("frontend-port")
profile := resolveProfile(cmd)
cfg, err := cli.LoadCLIConfigForProfile(profile)
if err != nil {
return err
}
cfg.AppURL = fmt.Sprintf("http://localhost:%d", frontendPort)
cfg.ServerURL = fmt.Sprintf("http://localhost:%d", port)
if err := cli.SaveCLIConfigForProfile(cfg, profile); err != nil {
return err
}
fmt.Fprintf(os.Stderr, "Configured for local deployment:\n")
fmt.Fprintf(os.Stderr, " app_url: %s\n", cfg.AppURL)
fmt.Fprintf(os.Stderr, " server_url: %s\n", cfg.ServerURL)
fmt.Fprintf(os.Stderr, "\nNext: run 'multica login' to authenticate.\n")
return nil
}
func valueOrDefault(v, fallback string) string {
if v == "" {

View File

@@ -1,10 +1,12 @@
package main
import (
"bufio"
"context"
"fmt"
"net/http"
"os"
"strings"
"time"
"github.com/spf13/cobra"
@@ -14,54 +16,177 @@ import (
var setupCmd = &cobra.Command{
Use: "setup",
Short: "One-command setup: configure, authenticate, and start the daemon",
Long: `Detects a local Multica server, configures the CLI, authenticates via browser,
and starts the agent daemon — all in one step.
Short: "Configure the CLI, authenticate, and start the daemon",
Long: `Configures the CLI to connect to Multica Cloud (multica.ai), then
authenticates via browser and starts the agent daemon.
Use --local to skip auto-detection and force local mode.`,
RunE: runSetup,
If a configuration already exists, you will be prompted before overwriting.
Use 'multica setup self-host' to connect to a self-hosted server instead.
Use --profile to create an isolated configuration for a separate environment:
multica setup self-host --profile staging --server-url https://api-staging.co`,
RunE: runSetupCloud,
}
var setupCloudCmd = &cobra.Command{
Use: "cloud",
Short: "Configure the CLI for Multica Cloud (multica.ai)",
Long: `Explicitly configures the CLI to connect to Multica Cloud (multica.ai).
This is equivalent to running 'multica setup' without a subcommand.`,
RunE: runSetupCloud,
}
var setupSelfHostCmd = &cobra.Command{
Use: "self-host",
Short: "Configure the CLI for a self-hosted Multica server",
Long: `Configures the CLI to connect to a self-hosted Multica server.
By default, connects to http://localhost:8080 (backend) and http://localhost:3000 (frontend).
Use --server-url and --app-url to specify a custom server (e.g. an on-premise deployment).
Examples:
multica setup self-host
multica setup self-host --server-url https://api.internal.co --app-url https://app.internal.co
multica setup self-host --port 9090 --frontend-port 4000`,
RunE: runSetupSelfHost,
}
func init() {
setupCmd.Flags().Bool("local", false, "Force local mode (skip server auto-detection)")
setupCmd.Flags().Int("port", 8080, "Backend server port (for local mode)")
setupCmd.Flags().Int("frontend-port", 3000, "Frontend port (for local mode)")
setupSelfHostCmd.Flags().String("server-url", "", "Backend server URL (e.g. https://api.internal.co)")
setupSelfHostCmd.Flags().String("app-url", "", "Frontend app URL (e.g. https://app.internal.co)")
setupSelfHostCmd.Flags().Int("port", 8080, "Backend server port (used when --server-url is not set)")
setupSelfHostCmd.Flags().Int("frontend-port", 3000, "Frontend port (used when --app-url is not set)")
setupCmd.AddCommand(setupCloudCmd)
setupCmd.AddCommand(setupSelfHostCmd)
}
func runSetup(cmd *cobra.Command, args []string) error {
forceLocal, _ := cmd.Flags().GetBool("local")
// printConfigLocation prints the config file path and profile name.
func printConfigLocation(profile string) {
path, err := cli.CLIConfigPathForProfile(profile)
if err != nil {
return
}
if profile != "" {
fmt.Fprintf(os.Stderr, " profile: %s\n", profile)
}
fmt.Fprintf(os.Stderr, " config: %s\n", path)
}
// confirmOverwrite checks for an existing config and prompts the user.
// Returns true if we should proceed, false if the user declined.
func confirmOverwrite(profile string) (bool, error) {
cfg, err := cli.LoadCLIConfigForProfile(profile)
if err != nil {
return true, nil // can't load → treat as no config
}
if cfg.ServerURL == "" {
return true, nil // no server configured → fresh config
}
fmt.Fprintln(os.Stderr, "Current configuration:")
fmt.Fprintf(os.Stderr, " server_url: %s\n", cfg.ServerURL)
fmt.Fprintf(os.Stderr, " app_url: %s\n", cfg.AppURL)
if cfg.WorkspaceID != "" {
fmt.Fprintf(os.Stderr, " workspace: %s\n", cfg.WorkspaceID)
}
fmt.Fprintln(os.Stderr, "")
fmt.Fprint(os.Stderr, "This will reset your configuration. Continue? [y/N] ")
reader := bufio.NewReader(os.Stdin)
answer, _ := reader.ReadString('\n')
answer = strings.TrimSpace(strings.ToLower(answer))
if answer != "y" && answer != "yes" {
fmt.Fprintln(os.Stderr, "Aborted.")
return false, nil
}
return true, nil
}
func runSetupCloud(cmd *cobra.Command, args []string) error {
profile := resolveProfile(cmd)
ok, err := confirmOverwrite(profile)
if err != nil {
return err
}
if !ok {
return nil
}
cfg := cli.CLIConfig{
ServerURL: "https://api.multica.ai",
AppURL: "https://multica.ai",
}
if err := cli.SaveCLIConfigForProfile(cfg, profile); err != nil {
return fmt.Errorf("save config: %w", err)
}
fmt.Fprintln(os.Stderr, "Configured for Multica Cloud (https://multica.ai).")
fmt.Fprintf(os.Stderr, " server_url: %s\n", cfg.ServerURL)
fmt.Fprintf(os.Stderr, " app_url: %s\n", cfg.AppURL)
printConfigLocation(profile)
// Authenticate.
fmt.Fprintln(os.Stderr, "")
if err := runLogin(cmd, args); err != nil {
return err
}
// Start daemon in background.
fmt.Fprintln(os.Stderr, "\nStarting daemon...")
if err := runDaemonBackground(cmd); err != nil {
return fmt.Errorf("start daemon: %w", err)
}
fmt.Fprintln(os.Stderr, "\n✓ Setup complete! Your machine is now connected to Multica.")
return nil
}
func runSetupSelfHost(cmd *cobra.Command, args []string) error {
profile := resolveProfile(cmd)
ok, err := confirmOverwrite(profile)
if err != nil {
return err
}
if !ok {
return nil
}
serverURL, _ := cmd.Flags().GetString("server-url")
appURL, _ := cmd.Flags().GetString("app-url")
port, _ := cmd.Flags().GetInt("port")
frontendPort, _ := cmd.Flags().GetInt("frontend-port")
profile := resolveProfile(cmd)
isLocal := forceLocal
if !forceLocal {
// Auto-detect a local server on the default port.
isLocal = probeLocalServer(port)
// If custom URLs provided, use them; otherwise default to localhost with ports.
if serverURL == "" {
serverURL = fmt.Sprintf("http://localhost:%d", port)
}
if appURL == "" {
appURL = fmt.Sprintf("http://localhost:%d", frontendPort)
}
if isLocal {
fmt.Fprintln(os.Stderr, "Detected local Multica server.")
cfg := cli.CLIConfig{
ServerURL: serverURL,
AppURL: appURL,
}
if err := cli.SaveCLIConfigForProfile(cfg, profile); err != nil {
return fmt.Errorf("save config: %w", err)
}
cfg, _ := cli.LoadCLIConfigForProfile(profile)
cfg.AppURL = fmt.Sprintf("http://localhost:%d", frontendPort)
cfg.ServerURL = fmt.Sprintf("http://localhost:%d", port)
if err := cli.SaveCLIConfigForProfile(cfg, profile); err != nil {
return fmt.Errorf("save config: %w", err)
}
fmt.Fprintln(os.Stderr, "Configured for self-hosted server.")
fmt.Fprintf(os.Stderr, " server_url: %s\n", cfg.ServerURL)
fmt.Fprintf(os.Stderr, " app_url: %s\n", cfg.AppURL)
printConfigLocation(profile)
fmt.Fprintf(os.Stderr, " app_url: %s\n", cfg.AppURL)
fmt.Fprintf(os.Stderr, " server_url: %s\n", cfg.ServerURL)
} else if !forceLocal {
fmt.Fprintln(os.Stderr, "No local server detected — using Multica Cloud (https://multica.ai).")
cfg, _ := cli.LoadCLIConfigForProfile(profile)
cfg.AppURL = "https://multica.ai"
cfg.ServerURL = "https://api.multica.ai"
if err := cli.SaveCLIConfigForProfile(cfg, profile); err != nil {
return fmt.Errorf("save config: %w", err)
}
// Check if the server is reachable.
if !probeServer(serverURL) {
fmt.Fprintf(os.Stderr, "\n⚠ Server at %s is not reachable.\n", serverURL)
fmt.Fprintln(os.Stderr, " Make sure the server is running, then run 'multica login'.")
return nil
}
// Authenticate.
@@ -80,9 +205,9 @@ func runSetup(cmd *cobra.Command, args []string) error {
return nil
}
// probeLocalServer checks whether a Multica backend is running on localhost.
func probeLocalServer(port int) bool {
url := fmt.Sprintf("http://localhost:%d/health", port)
// probeServer checks whether a Multica backend is reachable at the given URL.
func probeServer(baseURL string) bool {
url := strings.TrimRight(baseURL, "/") + "/health"
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()