Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,22 @@ npm run dev # open http://localhost:3000

After the UI opens: **Settings** → configure a model provider → open a workspace → click **Sync** → start chatting.

### Optional CLI

```bash
npm link
innoclaw
innoclaw run --prompt "Summarize the current workspace"
```

The CLI uses the same local app runtime as the web UI. When auth is enabled, it auto-starts the app, opens the browser login page on `localhost`, and stores a dedicated CLI session after sign-in. For headless automation, `DISABLE_AUTH=true` remains supported.

Headless local run mode:

```bash
DISABLE_AUTH=true npm run dev
```

> **Security**: InnoClaw includes shell execution and remote job submission capabilities. See [SECURITY.md](SECURITY.md) for deployment hardening and trust boundary documentation.

<details>
Expand Down Expand Up @@ -137,6 +153,7 @@ Go from code inspection to job submission and result analysis. Review repositori
#### 2026-05-12
- **Local User Authentication**: Added built-in account registration, sign-in, sign-out, and persistent session support.
- **Admin User Management**: Added an admin users page to create accounts and manage roles, access, passwords, and ownership.
- **CLI Login Handoff**: `innoclaw` now supports interactive terminal mode, one-shot `run`, JSON `batch`, and browser-to-CLI session handoff.


#### 2026-04-17
Expand Down Expand Up @@ -305,4 +322,3 @@ Go from code inspection to job submission and result analysis. Review repositori
- **License** — Apache-2.0, see `LICENSE`
- **Repository** — https://github.com/SpectrAI-Initiative/InnoClaw
- **Docs** — https://SpectrAI-Initiative.github.io/InnoClaw/

47 changes: 45 additions & 2 deletions dev-start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,58 @@ cd "$(dirname "$0")"

PORT=3000

server_responding() {
command -v curl >/dev/null 2>&1 || return 1
curl --noproxy "*" -fsS -o /dev/null -I "http://127.0.0.1:$PORT/login" >/dev/null 2>&1
}

pid_elapsed_seconds() {
ps -p "$1" -o etimes= 2>/dev/null | tr -d ' '
}

pid_workdir() {
readlink "/proc/$1/cwd" 2>/dev/null
}

is_repo_dev_process() {
local pid=$1
local cwd=$(pid_workdir "$pid")
local cmdline=$(ps -p "$pid" -o args= 2>/dev/null)
[ "$cwd" = "$PWD" ] && echo "$cmdline" | grep -qE "(npm run dev|next dev|node.*next)"
}

# Check if already running
if [ -f .dev.pid ]; then
PID=$(cat .dev.pid)
if ! echo "$PID" | grep -qE '^[0-9]+$'; then
echo "Invalid PID in .dev.pid, removing file"
rm -f .dev.pid
elif ps -p "$PID" > /dev/null 2>&1; then
echo "Dev server is already running (PID: $PID)"
exit 1
if server_responding; then
echo "Dev server is already running (PID: $PID)"
exit 0
fi

PID_AGE=$(pid_elapsed_seconds "$PID")
if is_repo_dev_process "$PID" && [ -n "$PID_AGE" ] && [ "$PID_AGE" -le 30 ]; then
echo "Dev server is still starting (PID: $PID, age: ${PID_AGE}s)"
exit 0
fi

if is_repo_dev_process "$PID"; then
echo "Dev server PID $PID is not healthy. Restarting it..."
kill "$PID" 2>/dev/null
sleep 2
if ps -p "$PID" > /dev/null 2>&1; then
echo "Force killing stale dev server..."
kill -9 "$PID" 2>/dev/null
sleep 1
fi
else
PID_CWD=$(pid_workdir "$PID")
echo ".dev.pid points to a live non-server process (PID: $PID${PID_CWD:+, cwd: $PID_CWD}). Removing stale file."
fi
rm -f .dev.pid
else
rm -f .dev.pid
fi
Expand Down
71 changes: 70 additions & 1 deletion docs/usage/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,72 @@

InnoClaw provides a set of REST API endpoints served by Next.js API routes. All endpoints are under the `/api/` path.

## Auth

### Login

```
POST /api/auth/login
```

Creates a browser session for a local user account.

### Register

```
POST /api/auth/register
```

Creates a local user account and signs the user in.

### Current Session

```
GET /api/auth/me
```

Returns the signed-in user and session expiry, or `401` if the request is unauthenticated.

### CLI Session Handoff

```
POST /api/auth/cli-session
```

Requires an authenticated browser session. Mints a fresh CLI session for the same user and returns the cookie triple needed by the terminal client.

**Request Body:**

```json
{
"nonce": "cli-login-nonce"
}
```

**Response:**

```json
{
"nonce": "cli-login-nonce",
"expiresAt": "2026-06-20T00:00:00.000Z",
"user": {
"id": "user-123",
"email": "user@example.com",
"name": "User",
"role": "user",
"isActive": true,
"lastLoginAt": null,
"createdAt": "2026-05-20T00:00:00.000Z",
"updatedAt": "2026-05-20T00:00:00.000Z"
},
"cookies": {
"innoclaw_session": "token",
"innoclaw_session_expires": "2026-06-20T00:00:00.000Z",
"innoclaw_session_sig": "signature"
}
}
```

## Workspaces

### List Workspaces
Expand All @@ -12,6 +78,8 @@ GET /api/workspaces

Returns all workspaces.

When auth is enabled, this endpoint requires a valid browser or CLI session cookie set. With `DISABLE_AUTH=true`, the headless admin compatibility path remains available.

**Response:**

```json
Expand All @@ -35,7 +103,8 @@ POST /api/workspaces

```json
{
"path": "/data/research/my-project"
"name": "my-project",
"folderPath": "/data/research/my-project"
}
```

Expand Down
10 changes: 9 additions & 1 deletion middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,19 @@ function isPublicApi(pathname: string): boolean {
return AUTH_PUBLIC_API_PREFIXES.some((prefix) => pathname.startsWith(prefix));
}

function hasCliHandoffParams(request: NextRequest): boolean {
return request.nextUrl.searchParams.has("cliCallback") && request.nextUrl.searchParams.has("cliNonce");
}

export async function middleware(request: NextRequest) {
if (process.env.DISABLE_AUTH === "true") {
return NextResponse.next();
}

const { pathname } = request.nextUrl;

if (isPublicPath(pathname) || isPublicApi(pathname)) {
if (AUTH_PUBLIC_PATHS.has(pathname) && await hasValidSessionMarker(request)) {
if (AUTH_PUBLIC_PATHS.has(pathname) && !hasCliHandoffParams(request) && await hasValidSessionMarker(request)) {
return NextResponse.redirect(new URL("/", request.url));
}
return NextResponse.next();
Expand Down
30 changes: 29 additions & 1 deletion plugins/innoclaw-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@

## What it provides

- `innoclaw` interactive TUI, using the current shell directory as the workspace
- `innoclaw run --prompt ...` for one-shot non-interactive agent runs
- `innoclaw batch --input ...` for JSON-driven batch runs
- `innoclaw auth status|login|logout`
- `innoclaw app dev|build|lint|test|start`
- `innoclaw doctor`
- `innoclaw workspace list|add`
- `innoclaw research list|create|show|run|export`

The Deep Research commands call the existing HTTP API exposed by the local Next.js app. By default the CLI targets `http://localhost:3000`, or `INNOCLAW_BASE_URL` if set.
The CLI keeps the local Next.js app as the runtime. By default it targets `http://localhost:3000`, auto-starts the local app when needed, opens the browser login page, and stores a dedicated CLI session for later reuse. For headless runs, start the app with `DISABLE_AUTH=true npm run dev`.

## Local usage

Expand All @@ -29,6 +33,11 @@ innoclaw --help
## Examples

```bash
innoclaw
innoclaw run --prompt "Summarize the current workspace"
printf 'Generate a plan for this repository' | innoclaw run
innoclaw batch --input jobs.json --workers 4
innoclaw auth login
innoclaw doctor
innoclaw app dev
innoclaw workspace list
Expand All @@ -37,3 +46,22 @@ innoclaw research create --workspace-id <workspace-id> --title "Survey of time-s
innoclaw research run --session-id <session-id>
innoclaw research export --session-id <session-id>
```

## Interactive login flow

When auth is enabled, the first interactive CLI command:

1. ensures the local app is running,
2. opens `http://localhost:3000/login` in your browser,
3. waits for browser sign-in or registration,
4. receives a dedicated CLI cookie triple through a localhost callback,
5. persists that CLI session in `~/.innoclaw/cli-sessions.json`.

The browser and CLI share the same user identity, but they do not reuse the same session token set.

## Headless run mode

```bash
DISABLE_AUTH=true npm run dev
innoclaw run --prompt "Summarize the current workspace"
```
Loading