Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
run: pnpm lint

- name: Format
run: pnpm format
run: pnpm format:check

- name: Typecheck
run: pnpm typecheck
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,6 @@ dist/
tests/eval-results/
.next/
.react-router/

# Local ideation artifacts
docs/
117 changes: 17 additions & 100 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,99 +2,29 @@

WorkOS CLI for installing AuthKit integrations and managing WorkOS resources (organizations, users, environments).

## Project Structure
## Architecture

```
src/
├── bin.ts # CLI entry point (yargs command routing)
├── cli.config.ts # App configuration (model, URLs, etc.)
├── run.ts # Installer orchestration entry point
├── lib/
│ ├── agent-interface.ts # Claude Agent SDK integration
│ ├── agent-runner.ts # Builds prompts, runs agent
│ ├── config.ts # Framework detection config
│ ├── constants.ts # Integration enum, shared constants
│ ├── credential-store.ts # OAuth credential storage (keyring + file fallback)
│ ├── config-store.ts # Environment config storage (keyring + file fallback)
│ ├── api-key.ts # API key resolution (env var → flag → config)
│ ├── workos-api.ts # Generic WorkOS REST API client
│ ├── credential-proxy.ts # Token refresh proxy for long sessions
│ └── ensure-auth.ts # Startup auth guard with token refresh
├── commands/
│ ├── env.ts # workos env (add/remove/switch/list)
│ ├── organization.ts # workos organization (create/update/get/list/delete)
│ ├── user.ts # workos user (get/list/update/delete)
│ ├── install.ts # workos install
│ └── login.ts / logout.ts # Auth commands
├── dashboard/ # Ink/React TUI components
├── nextjs/ # Next.js installer agent
├── react/ # React SPA installer agent
├── react-router/ # React Router installer agent
├── tanstack-start/ # TanStack Start installer agent
├── vanilla-js/ # Vanilla JS installer agent
└── utils/
└── table.ts # Terminal table formatter
```

## Key Architecture

- **Claude Agent SDK**: Uses `@anthropic-ai/claude-agent-sdk` to run Claude as an agent with tool access
- **Event Emitter**: `InstallerEventEmitter` bridges agent execution ↔ TUI for real-time updates
- **Framework Detection**: Each integration has a `detect()` function in `config.ts`
- **Permission Hook**: `installerCanUseTool()` in `agent-interface.ts` restricts Bash to safe commands only
- **Config Store**: `config-store.ts` stores environment configs (API keys, endpoints) in system keyring with file fallback
- **WorkOS API Client**: `workos-api.ts` is a generic fetch wrapper for any WorkOS REST endpoint
- Three adapters (CLI, Dashboard, Headless) subscribe to `InstallerEventEmitter` state machine events, selected by TTY detection
- `OutputMode` (`human`/`json`) resolved once at startup in `bin.ts`, drives all formatting
- `installerCanUseTool()` in `agent-interface.ts` restricts Bash to safe commands only
- Config/credentials stored in system keyring with file fallback

## CLI Modes
## Non-TTY Behavior

The installer supports two invocation modes:

### Regular CLI (default)

```bash
workos install
```

Streaming text output directly to terminal. Simple, lightweight, good for CI/scripts.

### TUI Dashboard (subcommand)

```bash
workos dashboard
```

Interactive Ink/React interface with real-time panels for:

- Agent thinking/reasoning
- File changes being made
- Tool execution status
- Progress indicators

The dashboard code lives in `src/dashboard/` and uses `InstallerEventEmitter` to receive updates from the agent.
- **Output**: Auto-switches to JSON when piped or `--json` flag. `WORKOS_FORCE_TTY=1` overrides.
- **Auth**: Exits code 4 instead of opening browser. Requires prior `workos login` or `WORKOS_API_KEY` env var.
- **Errors**: Structured JSON to stderr: `{ "error": { "code": "...", "message": "..." } }`
- **Exit codes**: 0=success, 1=error, 2=cancelled, 4=auth required (follows `gh` CLI convention)
- **Headless flags**: `--no-branch`, `--no-commit`, `--create-pr`, `--no-git-check`

## Tech Constraints

- **pnpm** only (not npm/yarn)
- **ESM** only - never use `require()`, `__dirname`, or CJS exports
- **Strict TypeScript** - no `as any`, proper typing required
- **No node-specific APIs** (crypto, fs sync, etc.) unless necessary
- **Ink + React 19** for TUI dashboard
- **Never commit the `docs/` directory** - it contains local ideation artifacts
- **pnpm** only
- Avoid Node-specific sync APIs (crypto, fs sync) unless necessary

## Commit Conventions

Use [Conventional Commits](https://www.conventionalcommits.org/) - release-please auto-generates changelog from these.

```
feat: add new feature → minor version bump, appears in changelog
fix: correct bug → patch version bump, appears in changelog
docs: update readme → no version bump
chore: update deps → no version bump
refactor: restructure code → no version bump
refactor!: breaking change → major version bump (or minor if pre-1.0)
```

Breaking changes: add `!` after type (e.g., `feat!:`) or include `BREAKING CHANGE:` in body.
[Conventional Commits](https://www.conventionalcommits.org/) — release-please auto-generates changelog. Use `!` suffix for breaking changes (e.g., `feat!:`).

## Commands

Expand All @@ -105,18 +35,6 @@ pnpm test # Run tests
pnpm typecheck # Type check
```

## Testing

```bash
# Run installer in a test project
cd /path/to/test-app && workos dashboard

# Test management commands
workos env add sandbox sk_test_xxx
workos organization list
workos user list
```

## Adding a New Framework

1. Create `src/{framework}/{framework}-installer-agent.ts`
Expand All @@ -126,7 +44,6 @@ workos user list

## Adding a New Resource Command

1. Create `src/commands/{resource}.ts` with command handlers (uses `workos-api.ts`)
2. Create `src/commands/{resource}.spec.ts` with mocked API tests
3. Register in `src/bin.ts` as a yargs command group with subcommands
4. Commands use `resolveApiKey()` from `api-key.ts` for auth
1. Create `src/commands/{resource}.ts` + `{resource}.spec.ts` (follow patterns in `organization.ts`)
2. Register in `src/bin.ts` and update `src/utils/help-json.ts` command registry
3. Include JSON mode tests in spec file
81 changes: 80 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ workos
- **Smart Detection:** Auto-detects framework, package manager, router type
- **Live Documentation:** Fetches latest SDK docs from WorkOS and GitHub
- **Full Integration:** Creates routes, middleware, environment vars, and UI
- **Agent & CI Ready:** Non-TTY auto-detection, JSON output, structured errors, headless installer with NDJSON streaming

## What It Creates

Expand Down Expand Up @@ -53,7 +54,7 @@ Commands:
login Authenticate with WorkOS via Connect OAuth device flow
logout Remove stored credentials
env Manage environment configurations
organization Manage organizations
organization (org) Manage organizations
user Manage users
doctor Diagnose WorkOS integration issues
install-skill Install AuthKit skills to coding agents
Expand Down Expand Up @@ -98,10 +99,16 @@ workos install [options]

--direct, -D Use your own Anthropic API key (bypass llm-gateway)
--integration <name> Framework: nextjs, react, react-router, tanstack-start, vanilla-js
--api-key <key> WorkOS API key (required in non-interactive mode)
--client-id <id> WorkOS client ID (required in non-interactive mode)
--redirect-uri <uri> Custom redirect URI
--homepage-url <url> Custom homepage URL
--install-dir <path> Installation directory
--no-validate Skip post-installation validation
--no-branch Skip branch creation (use current branch)
--no-commit Skip auto-commit after installation
--create-pr Auto-create pull request after installation
--no-git-check Skip git dirty working tree check
--force-install Force install packages even if peer dependency checks fail
--debug Enable verbose logging
```
Expand All @@ -117,6 +124,78 @@ npx workos --integration react-router

# With visual dashboard (experimental)
npx workos dashboard

# JSON output (explicit)
workos org list --json --api-key sk_test_xxx

# Pipe-friendly (auto-detects non-TTY)
workos org list --api-key sk_test_xxx | jq '.data[].name'

# Machine-readable command discovery
workos --help --json | jq '.commands[].name'
```

## Scripting & Automation

The CLI auto-detects non-TTY environments (piped output, CI, coding agents) and switches to machine-friendly behavior. No flags required — just pipe it.

### JSON Output

All commands produce structured JSON when piped or with `--json`:

```bash
workos org list --api-key sk_test_xxx | jq .
# → { "data": [...], "list_metadata": { "before": null, "after": "..." } }

workos env list --json
# → { "data": [{ "name": "prod", "type": "production", "active": true, ... }] }
```

Errors go to stderr as structured JSON:

```bash
workos org list 2>&1
# → { "error": { "code": "no_api_key", "message": "No API key configured..." } }
```

### Headless Installer

In non-TTY, the installer streams progress as NDJSON (one JSON object per line):

```bash
workos install --api-key sk_test_xxx --client-id client_xxx --no-commit 2>/dev/null
# → {"type":"detection:complete","integration":"nextjs","timestamp":"..."}
# → {"type":"agent:start","timestamp":"..."}
# → {"type":"agent:progress","message":"...","timestamp":"..."}
# → {"type":"complete","success":true,"timestamp":"..."}
```

### Exit Codes

| Code | Meaning |
| ---- | ----------------------- |
| 0 | Success |
| 1 | General error |
| 2 | Cancelled |
| 4 | Authentication required |

### Environment Variables

| Variable | Effect |
| ------------------------ | -------------------------------------------------------- |
| `WORKOS_API_KEY` | API key for management commands (bypasses stored config) |
| `WORKOS_NO_PROMPT=1` | Force non-interactive mode + JSON output |
| `WORKOS_FORCE_TTY=1` | Force interactive mode even when piped |
| `WORKOS_TELEMETRY=false` | Disable telemetry |

### Command Discovery

Agents can introspect available commands:

```bash
workos --help --json # Full command tree
workos env --help --json # Subcommand tree
workos organization --help --json # With positionals and option types
```

## Authentication
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@
"build": "pnpm tsc",
"postbuild": "chmod +x ./dist/bin.js && cp -r scripts/** dist",
"lint": "oxlint",
"format": "oxfmt --check .",
"format": "oxfmt .",
"format:check": "oxfmt --check .",
"try": "tsx dev.ts",
"dev": "pnpm build && pnpm link --global && pnpm build:watch",
"test": "vitest run",
Expand Down
Loading