arcade-mcp/libs/arcade-cli/arcade_cli/templates/base.jinja
Nate Barbettini aae9b3a49c
feat: Support multiple orgs & projects in Arcade CLI (#717)
Fixes [PLT-720: Refactor CLI to support multiple orgs +
projects](https://linear.app/arcadedev/issue/PLT-720/refactor-cli-to-support-multiple-orgs-projects)

This PR removes the legacy login flow (login to get an API key) from
Arcade CLI. Believe it or not, this flow predates the ability to get an
API key from the Dashboard, or even the Dashboard itself!

Notable changes:

**Legacy handling** - When a user with an existing `credentials.yaml`
updates the CLI, they will get instructions on fixing their old
credentials:
<img width="978" height="146" alt="Screenshot 2025-12-08 at 10 10 37"
src="https://github.com/user-attachments/assets/5aeaef2c-bef7-4642-a2f7-f917b257c94b"
/>

Any commands that require login (non-public commands) will be blocked
with the above message until `arcade logout / arcade login` is performed
again.

**New login flow**

```sh
arcade login
Opening a browser to log you in...

 Logged in as nate@arcade.dev.

Active project: Nate Barbettini's organization / Default project
Run 'arcade org list' or 'arcade project list' to see available options.
```

**List and set the active organization**
```sh
arcade org list
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━┓
┃ Name                           ┃ ID                                   ┃ Default ┃ Active ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━┩
│ Nate Barbettini's organization │ 1c64968e-fdc5-4c55-8612-2ce46cd7881b │ ✓       │ ✓      │
│ Sergio 743                     │ 1f1f6184-58dc-4bac-bdde-b9184e43fdf3 │         │        │
└────────────────────────────────┴──────────────────────────────────────┴─────────┴────────┘

Use 'arcade org set <org_id>' to switch organizations.
```
```sh
arcade org set 1c64968e-fdc5-4c55-8612-2ce46cd7881b 

✓ Switched to organization: Nate Barbettini's organization
  Active project: Default project
```

**List and set the active project**
```sh
arcade project list

Active organization: Nate Barbettini's organization
Use 'arcade org list' and 'arcade org set <org_id>' to switch organizations.

┏━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━┓
┃ Name            ┃ ID                                   ┃ Default ┃ Active ┃
┡━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━┩
│ Default project │ 35166bf3-6e68-481e-bf16-f747fadc6c22 │ ✓       │ ✓      │
│ Second project  │ 62963205-31ea-4fda-9fc4-af10db89c06f │         │        │
└─────────────────┴──────────────────────────────────────┴─────────┴────────┘

Use 'arcade project set <project_id>' to switch projects.
```
```sh
arcade project set 35166bf3-6e68-481e-bf16-f747fadc6c22
✓ Switched to project: Default project
```

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Migrates CLI to OAuth2 (PKCE) with saved org/project context, adds
org/project commands, rewrites Engine calls to org-scoped endpoints, and
bumps core packages.
> 
> - **Auth & Config**
> - Implement OAuth2 Authorization Code + PKCE (`arcade_cli/authn.py`)
with local callback server and Jinja templates.
> - Persist tokens and active `context` (org/project) in
`credentials.yaml` via updated config models
(`arcade_core/config_model.py`).
> - Add token refresh and CLI config fetch utilities
(`arcade_core/auth_tokens.py`).
> - Detect legacy API-key credentials and block protected commands until
re-login; add `whoami` command.
> - **Org/Project Management**
> - New subcommands: `arcade org list|set`, `arcade project list|set`
(fetch via Coordinator).
> - **Engine API usage (org-scoped)**
> - Introduce org/project URL rewriting transports
(`arcade_core/network/org_transport.py`) and helpers
(`get_org_scoped_url`, `get_arcade_client`, `get_auth_headers`).
> - Update `deploy`, `server`, and `secret` commands to use Bearer
tokens and org-scoped paths; adjust log streaming/status, secrets CRUD,
and deployment workflows.
> - **CLI UX**
> - Replace legacy login URLs/constants; add success/failure HTML
templates for browser callback.
>   - Tweak `dashboard` to health-check without credentials.
>   - Usage tracking now includes `org_id`/`project_id` properties.
> - **Tests**
> - Update tests for dashboard, secrets, utils, and usage identity
(OAuth `/whoami`).
> - **Dependencies & Versions**
> - Bump packages: `arcade-core@4.0.0`, `arcade-mcp-server@1.12.0`,
`arcade-serve@3.2.0`, `arcade-tdk@3.3.0`; add `authlib`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
49702c2f74b9db15bb286d3ec71179b4e74a9134. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
2025-12-11 12:58:55 -08:00

152 lines
3.8 KiB
Django/Jinja

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{% block title %}{% endblock %}</title>
<link rel="icon" type="image/svg+xml" href="https://cdn.arcade.dev/favicons/favicon.svg" />
<link
rel="icon"
type="image/png"
sizes="32x32"
href="https://cdn.arcade.dev/favicons/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="https://cdn.arcade.dev/favicons/favicon-16x16.png"
/>
<link
rel="apple-touch-icon"
sizes="180x180"
href="https://cdn.arcade.dev/favicons/apple-touch-icon.png"
/>
<style>
:root {
color-scheme: dark;
}
*, *::before, *::after {
box-sizing: border-box;
}
body {
min-height: 100vh;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: radial-gradient(circle at top, color-mix(in srgb, var(--primary, #ED155D) 20%, transparent), #050505 55%);
color: var(--text-primary, #f7f7f7);
display: flex;
justify-content: center;
align-items: center;
padding: clamp(24px, 5vw, 48px);
}
h1, h2, h3, h4, h5, h6 {
margin: 0;
line-height: 1.3;
}
h2 {
font-size: clamp(1.75rem, 4vw, 2rem);
font-weight: 600;
color: var(--text-primary, #ffffff);
}
p {
margin: 0;
line-height: 1.6;
}
.container {
width: min(560px, 100%);
}
.arc-card {
background: var(--surface-card, rgba(18, 18, 18, 0.92));
border: 1px solid color-mix(in srgb, var(--border-default, #2c2c2c) 65%, transparent);
border-radius: 24px;
box-shadow: var(--shadow-lg, 0 25px 60px rgba(0, 0, 0, 0.55));
padding: clamp(32px, 6vw, 48px);
display: flex;
flex-direction: column;
gap: 32px;
}
.arc-logo {
display: block;
width: 80px;
height: 80px;
margin: 0 auto;
}
.arc-heading {
margin: 0;
text-align: center;
font-size: 1.5rem;
font-weight: 600;
color: var(--text-primary, #ffffff);
}
a {
color: var(--primary, #ED155D);
text-decoration: none;
}
a:hover {
color: color-mix(in srgb, var(--primary, #ED155D), #ffffff 20%);
}
.branding {
border-top: 1px solid color-mix(in srgb, var(--border-default, #2a2a2a), transparent 30%);
padding-top: 24px;
text-align: center;
display: flex;
flex-direction: column;
gap: 8px;
}
.branding-text {
font-size: 0.875rem;
color: var(--text-muted, #bcbcbc);
}
.docs-link {
color: var(--primary, #ED155D);
text-decoration: none;
font-weight: 500;
transition: color 0.2s ease;
}
.docs-link:hover {
color: color-mix(in srgb, var(--primary, #ED155D), #ffffff 20%);
text-decoration: underline;
}
{% block styles %}{% endblock %}
</style>
{% block scripts %}{% endblock %}
</head>
<body>
<main class="container">
<section class="arc-card" aria-live="polite">
<img
src="https://cdn.arcade.dev/logos/circle_texture.png"
width="80"
height="80"
alt="Arcade.dev logo"
class="arc-logo"
/>
{% set heading_block %}{% block heading %}{% endblock %}{% endset %}
{% if heading_block | trim %}
<h2 class="arc-heading">{{ heading_block | trim | safe }}</h2>
{% endif %}
{% block content %}{% endblock %}
</section>
</main>
</body>
</html>