mirror of
https://github.com/multica-ai/multica.git
synced 2026-06-24 07:59:30 +02:00
Compare commits
1 Commits
fix/header
...
jiayuan/in
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
606a515f91 |
@@ -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
|
||||
|
||||
2
Makefile
2
Makefile
@@ -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:"; \
|
||||
|
||||
21
README.md
21
README.md
@@ -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 |
|
||||
|
||||
@@ -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`)。
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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",
|
||||
],
|
||||
|
||||
@@ -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)",
|
||||
"项目列表页支持行内编辑属性(优先级、状态、负责人)",
|
||||
],
|
||||
|
||||
@@ -77,6 +77,10 @@ export class ApiClient {
|
||||
this.logger = options?.logger ?? noopLogger;
|
||||
}
|
||||
|
||||
getBaseUrl(): string {
|
||||
return this.baseUrl;
|
||||
}
|
||||
|
||||
setToken(token: string | null) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 == "" {
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user