cinna-cli 0.2.6__tar.gz → 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/.gitignore +1 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/PKG-INFO +41 -5
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/README.md +40 -4
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/README.md +16 -5
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/account_workspace/account_workspace.md +85 -7
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/account_workspace/account_workspace_acceptance.md +110 -3
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/account_workspace/account_workspace_tech.md +92 -12
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/bootstrap_onboarding/bootstrap_onboarding.md +44 -6
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/bootstrap_onboarding/bootstrap_onboarding_acceptance.md +45 -1
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/bootstrap_onboarding/bootstrap_onboarding_tech.md +97 -6
- cinna_cli-0.4.0/docs/features/local_agent_import/local_agent_import.md +181 -0
- cinna_cli-0.4.0/docs/features/local_agent_import/local_agent_import_acceptance.md +264 -0
- cinna_cli-0.4.0/docs/features/local_agent_import/local_agent_import_tech.md +389 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/pyproject.toml +1 -1
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/src/cinna/account.py +228 -30
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/src/cinna/bootstrap.py +1 -2
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/src/cinna/chat.py +1 -1
- cinna_cli-0.4.0/src/cinna/cli_version.py +111 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/src/cinna/client.py +14 -0
- cinna_cli-0.4.0/src/cinna/console.py +187 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/src/cinna/doctor.py +46 -3
- cinna_cli-0.4.0/src/cinna/errors.py +212 -0
- cinna_cli-0.4.0/src/cinna/kit_contract.py +857 -0
- cinna_cli-0.4.0/src/cinna/local_import.py +1131 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/src/cinna/main.py +223 -25
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/src/cinna/mutagen_runtime.py +40 -9
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/src/cinna/sync.py +20 -1
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/src/cinna/sync_session.py +2 -1
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/src/cinna/sync_tui.py +6 -9
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/src/cinna/templates/ACCOUNT_CLAUDE.md.template +5 -1
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/tests/conftest.py +10 -0
- cinna_cli-0.4.0/tests/test_cli_version.py +55 -0
- cinna_cli-0.4.0/tests/test_kit_contract.py +433 -0
- cinna_cli-0.4.0/tests/test_local_import.py +1238 -0
- cinna_cli-0.4.0/tests/test_onboarding.py +800 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/tests/test_sync.py +42 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/uv.lock +1 -1
- cinna_cli-0.2.6/src/cinna/console.py +0 -39
- cinna_cli-0.2.6/src/cinna/errors.py +0 -66
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/.claude/commands/cinna-cli.feature.doc.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/.github/workflows/publish.yml +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/LICENSE.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/agent_api/agent_api.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/agent_api/agent_api_acceptance.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/agent_api/agent_api_tech.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/agent_management/agent_management.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/agent_management/agent_management_acceptance.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/agent_management/agent_management_tech.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/agent_schedules/agent_schedules.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/agent_schedules/agent_schedules_acceptance.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/agent_schedules/agent_schedules_tech.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/doctor/doctor.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/doctor/doctor_acceptance.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/doctor/doctor_tech.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/git_versioning/git_versioning.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/git_versioning/git_versioning_acceptance.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/git_versioning/git_versioning_tech.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/improvement_requests/improvement_requests.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/improvement_requests/improvement_requests_acceptance.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/improvement_requests/improvement_requests_tech.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/live_sync/live_sync.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/live_sync/live_sync_acceptance.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/live_sync/live_sync_tech.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/mcp_integration/mcp_integration.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/mcp_integration/mcp_integration_acceptance.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/mcp_integration/mcp_integration_tech.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/remote_chat/remote_chat.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/remote_chat/remote_chat_acceptance.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/remote_chat/remote_chat_tech.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/remote_exec/remote_exec.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/remote_exec/remote_exec_acceptance.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/remote_exec/remote_exec_tech.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/interface.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/mutagen_capabilities.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/scripts/check_docs_references.py +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/src/cinna/__init__.py +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/src/cinna/auth.py +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/src/cinna/config.py +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/src/cinna/context.py +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/src/cinna/git_versioning.py +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/src/cinna/improve.py +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/src/cinna/logging.py +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/src/cinna/mcp_proxy.py +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/src/cinna/sync_ssh_shim.py +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/src/cinna/templates/CHAT_TESTING.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/src/cinna/templates/CLAUDE.md.template +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/src/cinna/templates/GIT_VERSIONING.md +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/src/cinna/templates/__init__.py +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/tests/__init__.py +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/tests/test_account.py +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/tests/test_auth.py +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/tests/test_bootstrap.py +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/tests/test_chat.py +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/tests/test_client.py +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/tests/test_config.py +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/tests/test_context.py +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/tests/test_doctor.py +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/tests/test_git_versioning.py +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/tests/test_improve.py +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/tests/test_main.py +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/tests/test_mutagen_runtime.py +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/tests/test_sync_session.py +0 -0
- {cinna_cli-0.2.6 → cinna_cli-0.4.0}/tests/test_sync_ssh_shim.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: cinna-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Local development CLI for Cinna Core agents
|
|
5
5
|
Project-URL: Homepage, https://github.com/opencinna/cinna-cli
|
|
6
6
|
Project-URL: Repository, https://github.com/opencinna/cinna-cli
|
|
@@ -63,7 +63,11 @@ Your Editor / Claude Code
|
|
|
63
63
|
## Prerequisites
|
|
64
64
|
|
|
65
65
|
- **Python 3.10+**
|
|
66
|
-
- **[Mutagen](https://mutagen.io)** (version pinned by the platform — `cinna setup` checks and prompts to install)
|
|
66
|
+
- **[Mutagen](https://mutagen.io)** (version pinned by the platform — `cinna setup` checks and prompts to install; set `CINNA_MUTAGEN_BIN=/abs/path/mutagen` to use a specific binary instead of the one on PATH)
|
|
67
|
+
|
|
68
|
+
### Cinna Desktop
|
|
69
|
+
|
|
70
|
+
[Cinna Desktop](https://github.com/opencinna/cinna-desktop) installs its **own pinned copy** of cinna-cli (with `uv` and Mutagen alongside, inside its data folder) and drives it as a child process to create and keep alive an account workspace under `<AgentsHome>/Cloud/<host>/` right after you sign in — no `cinna login`, no token to paste. That private copy is not on your `PATH` unless you opt in from the desktop's settings; installing cinna-cli yourself (`uv tool install cinna-cli`) for terminal use is fine and both operate on the same workspace. The version the platform pins is reported by `cinna account status` / `cinna doctor`.
|
|
67
71
|
|
|
68
72
|
## Getting Started
|
|
69
73
|
|
|
@@ -135,7 +139,7 @@ cinna login app.example.com --dir my-cinna # always into a named sub
|
|
|
135
139
|
# ✓ Account workspace ready.
|
|
136
140
|
```
|
|
137
141
|
|
|
138
|
-
Use it when `cinna account status` or `cinna doctor` reports the account token has expired. Because the per-agent tokens minted from an account (`cinna agent sync`) can only be re-minted while the account token is valid, the flow is: `cinna login` (refresh the account), then `cinna doctor` (re-mint the dependent sub-agent tokens). If the platform doesn't expose the device-login endpoints yet, `cinna login` says so and points you at the `cinna account
|
|
142
|
+
Use it when `cinna account status` or `cinna doctor` reports the account token has expired. Because the per-agent tokens minted from an account (`cinna agent sync`) can only be re-minted while the account token is valid, the flow is: `cinna login` (refresh the account), then `cinna doctor` (re-mint the dependent sub-agent tokens). If the platform doesn't expose the device-login endpoints yet, `cinna login` says so and points you at the `cinna account set-token` paste fallback.
|
|
139
143
|
|
|
140
144
|
### `cinna account setup <token_or_url>`
|
|
141
145
|
|
|
@@ -145,7 +149,7 @@ Initialize an **account workspace** — a multi-agent root from which you can di
|
|
|
145
149
|
curl -sL https://your-platform.com/api/cli-setup/account/TOKEN | python3 -
|
|
146
150
|
```
|
|
147
151
|
|
|
148
|
-
Accepts the same input forms as `cinna setup` (full curl command, URL, or bare token — bare tokens need `CINNA_PLATFORM_URL`). Creates
|
|
152
|
+
Accepts the same input forms as `cinna setup` (full curl command, URL, or bare token — bare tokens need `CINNA_PLATFORM_URL`). Creates a folder named after the platform domain (override with `--dir`: an absolute path is used as is with parents created, a relative one lands under the current directory; an existing account workspace there is refused before the token is spent) containing:
|
|
149
153
|
|
|
150
154
|
```
|
|
151
155
|
my-cinna/
|
|
@@ -159,6 +163,17 @@ Setup also downloads the **context package** into `context/` — curated platfor
|
|
|
159
163
|
|
|
160
164
|
The account token is only used for the account-level endpoints (listing agents, minting per-agent tokens, the context package). Per-agent work always runs on each child workspace's own token. Revoking the account session in Settings disconnects every agent synced from it.
|
|
161
165
|
|
|
166
|
+
`account setup`, `account set-token` and `account status` take `--no-input` (never prompt: defaults, or fail with code `needs_input`; also `CINNA_NO_INPUT=1`, accepted before or after the subcommand) and `--json` (one JSON object per line on stdout — progress `{"step","total","status","message"}` lines, then a final `{"result":"ok"|"error",…}`; implies `--no-input`). Exit codes are stable for every command: `0` ok, `10` setup token invalid/expired/used, `11` token for another account, `12` platform unreachable or 5xx, `1` anything else (the JSON `code` says what), `2` usage.
|
|
167
|
+
|
|
168
|
+
### `cinna account set-token <token_or_url>`
|
|
169
|
+
|
|
170
|
+
Refresh the **account** token in place from a fresh account setup token — the account counterpart of `cinna set-token`, and the paste alternative to `cinna login`. Run inside the account workspace; it re-exchanges under the stored machine name and rewrites only `account_token` (plus a refreshed platform/frontend URL) in `.cinna/account.json`. The active user workspace, machine name, `context/` and every synced child under `agents/` are untouched; run `cinna doctor` afterwards to re-mint expired child tokens. A token for a different account is refused (exit `11`) and nothing is written. Bare tokens reuse the stored platform URL.
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
cd my-cinna/
|
|
174
|
+
cinna account set-token 'curl -sL https://your-platform.com/api/cli-setup/account/TOKEN | python3 -'
|
|
175
|
+
```
|
|
176
|
+
|
|
162
177
|
### `cinna account agents`
|
|
163
178
|
|
|
164
179
|
List the agents your account can access (run from inside the account workspace). For each agent: display name + ID, building rights (`✓ can build`, `view-only`, or `foreign install` — installed bundles are publisher-managed and can't be synced), whether a remote environment is active, and whether a local workspace already exists under `agents/`.
|
|
@@ -167,7 +182,9 @@ List the agents your account can access (run from inside the account workspace).
|
|
|
167
182
|
|
|
168
183
|
One-shot summary of the account workspace: platform/frontend URLs, machine name, synced-agent count, and an account-token probe (`valid token` / `expired token` / `no connection`) — the account-level counterpart of `cinna status`.
|
|
169
184
|
|
|
170
|
-
Also reports the workspace's **context package version** against the platform's current one — the orchestrator guides ship in that tree, so a workspace set up before a guide existed silently lacks it. When it is behind, the command says so and points at `cinna account refresh-context`; `cinna improve list` prints the same nudge, since its playbook lives there.
|
|
185
|
+
Also reports the workspace's **context package version** against the platform's current one — the orchestrator guides ship in that tree, so a workspace set up before a guide existed silently lacks it. When it is behind, the command says so and points at `cinna account refresh-context`; `cinna improve list` prints the same nudge, since its playbook lives there. Likewise it compares the installed **cinna-cli version** with the one the platform pins (its `/.well-known/cinna-desktop` discovery document) and suggests `uv tool install cinna-cli==<pin>` when behind; no pin means "unknown", not an error.
|
|
186
|
+
|
|
187
|
+
With `--json` it prints a single line: `{"result":"ok","workspace",…,"token":"valid|expired|unreachable","synced_agents":N,"agents":[…],"context_package":{"local","remote","state"},"cli":{"installed","required","state"}}`.
|
|
171
188
|
|
|
172
189
|
### `cinna account refresh-context`
|
|
173
190
|
|
|
@@ -259,6 +276,25 @@ works exactly as for a manually set-up agent. Synced agents also appear in `cinn
|
|
|
259
276
|
|
|
260
277
|
Detach a synced workspace: stop its sync session, revoke the minted CLI token server-side (via the account-scoped revoke endpoint, authenticated with the account token; idempotent), then perform the equivalent of `cinna disconnect`: remove `.cinna/`, generated files, and the registry entry. Workspace files under `agents/<slug>/workspace/` are preserved. The revoke degrades gracefully — if it fails (no connection, or a workspace synced before token-id tracking), a warning is printed and the local teardown still completes; the token then expires on its own or can be revoked from the agent's Integrations tab.
|
|
261
278
|
|
|
279
|
+
### `cinna agent import <path> [--name TEXT] [--workspace REF] [--update] [--dry-run] [--no-push] [--yes]`
|
|
280
|
+
|
|
281
|
+
Import an agent that was built **locally** with the [Local Agent Kit](docs/features/local_agent_import/local_agent_import.md) — a folder holding a `cinna-agent.json` manifest, typically `../Local/<slug>` next to this account workspace. Run it from the account workspace root (or any folder inside it).
|
|
282
|
+
|
|
283
|
+
Nine idempotent steps, each printed as `[n/9]`: read and validate the manifest → create (or resolve) the cloud agent → write its description, router trigger, example prompts and the three document prompts in one bulk write, plus the status refresh command → attach a local workspace (`cinna agent sync`) → copy the tree into `agents/<slug>/workspace/` honouring the contract's exclude list and secret rules, generating `workspace_requirements.txt` from `pyproject.toml` when the agent doesn't ship one → `cinna sync push` → create the credential drafts and attach them → create the schedules → record the publication in `publications.json` and print the summary.
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
cinna agent import ../Local/invoice-watcher --dry-run # see the plan, touch nothing
|
|
287
|
+
cinna agent import ../Local/invoice-watcher --yes
|
|
288
|
+
cinna chat --agent invoice-watcher "check invoices from last week"
|
|
289
|
+
|
|
290
|
+
# after more local work:
|
|
291
|
+
cinna agent import ../Local/invoice-watcher --update --yes
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
The folder rules come from the kit's versioned contract, `.cinna-kit/layout.json` — the same file Cinna Desktop reads — so a correction published there reaches this command on the next kit refresh rather than waiting for a new cinna-cli. `credentials/` and `app-data/` are **never** copied, not even if the contract drops them, and on top of the exclude list the contract's `secret_files` rules withhold every dotenv shape (`.env`, `.env.prod`, `staging.env`) wherever it sits, while `.env.example` still travels. No secret value is ever read, sent, or printed: credentials are created as empty drafts and the command prints the URLs the user opens to fill them in the browser.
|
|
295
|
+
|
|
296
|
+
Where the folder has been published is recorded in `publications.json`, a **sibling** of `cinna-agent.json` holding one entry per Cinna instance — it cannot live inside the manifest, because each entry records a hash of the exported tree and the manifest is part of that tree. Every step is idempotent (agent by the entry whose `platform_url` matches the instance you are logged into, credentials by name, schedules by name), so a partial import is resumed with `--update` instead of duplicating anything. The publication is recorded **only after the push settled** — `--no-push`, a failed flush, or remaining conflicts leave it unrecorded, and the next run is a plain `--update`. A legacy `cloud` block is migrated into the ledger on the first write and is still read until then, so an older folder's `--update` never creates a second agent. `--dry-run` makes no platform call and writes nothing.
|
|
297
|
+
|
|
262
298
|
### `cinna connect agent-api --producer <agent> --consumer <agent> [--label TEXT] [--read-only]`
|
|
263
299
|
|
|
264
300
|
Wire one agent to another's REST API from the account workspace. Resolves both agents (name, slug, or ID), mints a producer API token, and attaches it to the consumer as a credential — which rides the consumer's normal credential sync into its remote environment, so no key ever touches your machine. Prints the credential ID, token prefix, base URL, and spec URL. `--read-only` restricts the consumer to read-only access; `--label` names the credential. Backend errors surface verbatim: 400 if the producer's REST API is disabled, 403/404 for ownership violations.
|
|
@@ -26,7 +26,11 @@ Your Editor / Claude Code
|
|
|
26
26
|
## Prerequisites
|
|
27
27
|
|
|
28
28
|
- **Python 3.10+**
|
|
29
|
-
- **[Mutagen](https://mutagen.io)** (version pinned by the platform — `cinna setup` checks and prompts to install)
|
|
29
|
+
- **[Mutagen](https://mutagen.io)** (version pinned by the platform — `cinna setup` checks and prompts to install; set `CINNA_MUTAGEN_BIN=/abs/path/mutagen` to use a specific binary instead of the one on PATH)
|
|
30
|
+
|
|
31
|
+
### Cinna Desktop
|
|
32
|
+
|
|
33
|
+
[Cinna Desktop](https://github.com/opencinna/cinna-desktop) installs its **own pinned copy** of cinna-cli (with `uv` and Mutagen alongside, inside its data folder) and drives it as a child process to create and keep alive an account workspace under `<AgentsHome>/Cloud/<host>/` right after you sign in — no `cinna login`, no token to paste. That private copy is not on your `PATH` unless you opt in from the desktop's settings; installing cinna-cli yourself (`uv tool install cinna-cli`) for terminal use is fine and both operate on the same workspace. The version the platform pins is reported by `cinna account status` / `cinna doctor`.
|
|
30
34
|
|
|
31
35
|
## Getting Started
|
|
32
36
|
|
|
@@ -98,7 +102,7 @@ cinna login app.example.com --dir my-cinna # always into a named sub
|
|
|
98
102
|
# ✓ Account workspace ready.
|
|
99
103
|
```
|
|
100
104
|
|
|
101
|
-
Use it when `cinna account status` or `cinna doctor` reports the account token has expired. Because the per-agent tokens minted from an account (`cinna agent sync`) can only be re-minted while the account token is valid, the flow is: `cinna login` (refresh the account), then `cinna doctor` (re-mint the dependent sub-agent tokens). If the platform doesn't expose the device-login endpoints yet, `cinna login` says so and points you at the `cinna account
|
|
105
|
+
Use it when `cinna account status` or `cinna doctor` reports the account token has expired. Because the per-agent tokens minted from an account (`cinna agent sync`) can only be re-minted while the account token is valid, the flow is: `cinna login` (refresh the account), then `cinna doctor` (re-mint the dependent sub-agent tokens). If the platform doesn't expose the device-login endpoints yet, `cinna login` says so and points you at the `cinna account set-token` paste fallback.
|
|
102
106
|
|
|
103
107
|
### `cinna account setup <token_or_url>`
|
|
104
108
|
|
|
@@ -108,7 +112,7 @@ Initialize an **account workspace** — a multi-agent root from which you can di
|
|
|
108
112
|
curl -sL https://your-platform.com/api/cli-setup/account/TOKEN | python3 -
|
|
109
113
|
```
|
|
110
114
|
|
|
111
|
-
Accepts the same input forms as `cinna setup` (full curl command, URL, or bare token — bare tokens need `CINNA_PLATFORM_URL`). Creates
|
|
115
|
+
Accepts the same input forms as `cinna setup` (full curl command, URL, or bare token — bare tokens need `CINNA_PLATFORM_URL`). Creates a folder named after the platform domain (override with `--dir`: an absolute path is used as is with parents created, a relative one lands under the current directory; an existing account workspace there is refused before the token is spent) containing:
|
|
112
116
|
|
|
113
117
|
```
|
|
114
118
|
my-cinna/
|
|
@@ -122,6 +126,17 @@ Setup also downloads the **context package** into `context/` — curated platfor
|
|
|
122
126
|
|
|
123
127
|
The account token is only used for the account-level endpoints (listing agents, minting per-agent tokens, the context package). Per-agent work always runs on each child workspace's own token. Revoking the account session in Settings disconnects every agent synced from it.
|
|
124
128
|
|
|
129
|
+
`account setup`, `account set-token` and `account status` take `--no-input` (never prompt: defaults, or fail with code `needs_input`; also `CINNA_NO_INPUT=1`, accepted before or after the subcommand) and `--json` (one JSON object per line on stdout — progress `{"step","total","status","message"}` lines, then a final `{"result":"ok"|"error",…}`; implies `--no-input`). Exit codes are stable for every command: `0` ok, `10` setup token invalid/expired/used, `11` token for another account, `12` platform unreachable or 5xx, `1` anything else (the JSON `code` says what), `2` usage.
|
|
130
|
+
|
|
131
|
+
### `cinna account set-token <token_or_url>`
|
|
132
|
+
|
|
133
|
+
Refresh the **account** token in place from a fresh account setup token — the account counterpart of `cinna set-token`, and the paste alternative to `cinna login`. Run inside the account workspace; it re-exchanges under the stored machine name and rewrites only `account_token` (plus a refreshed platform/frontend URL) in `.cinna/account.json`. The active user workspace, machine name, `context/` and every synced child under `agents/` are untouched; run `cinna doctor` afterwards to re-mint expired child tokens. A token for a different account is refused (exit `11`) and nothing is written. Bare tokens reuse the stored platform URL.
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
cd my-cinna/
|
|
137
|
+
cinna account set-token 'curl -sL https://your-platform.com/api/cli-setup/account/TOKEN | python3 -'
|
|
138
|
+
```
|
|
139
|
+
|
|
125
140
|
### `cinna account agents`
|
|
126
141
|
|
|
127
142
|
List the agents your account can access (run from inside the account workspace). For each agent: display name + ID, building rights (`✓ can build`, `view-only`, or `foreign install` — installed bundles are publisher-managed and can't be synced), whether a remote environment is active, and whether a local workspace already exists under `agents/`.
|
|
@@ -130,7 +145,9 @@ List the agents your account can access (run from inside the account workspace).
|
|
|
130
145
|
|
|
131
146
|
One-shot summary of the account workspace: platform/frontend URLs, machine name, synced-agent count, and an account-token probe (`valid token` / `expired token` / `no connection`) — the account-level counterpart of `cinna status`.
|
|
132
147
|
|
|
133
|
-
Also reports the workspace's **context package version** against the platform's current one — the orchestrator guides ship in that tree, so a workspace set up before a guide existed silently lacks it. When it is behind, the command says so and points at `cinna account refresh-context`; `cinna improve list` prints the same nudge, since its playbook lives there.
|
|
148
|
+
Also reports the workspace's **context package version** against the platform's current one — the orchestrator guides ship in that tree, so a workspace set up before a guide existed silently lacks it. When it is behind, the command says so and points at `cinna account refresh-context`; `cinna improve list` prints the same nudge, since its playbook lives there. Likewise it compares the installed **cinna-cli version** with the one the platform pins (its `/.well-known/cinna-desktop` discovery document) and suggests `uv tool install cinna-cli==<pin>` when behind; no pin means "unknown", not an error.
|
|
149
|
+
|
|
150
|
+
With `--json` it prints a single line: `{"result":"ok","workspace",…,"token":"valid|expired|unreachable","synced_agents":N,"agents":[…],"context_package":{"local","remote","state"},"cli":{"installed","required","state"}}`.
|
|
134
151
|
|
|
135
152
|
### `cinna account refresh-context`
|
|
136
153
|
|
|
@@ -222,6 +239,25 @@ works exactly as for a manually set-up agent. Synced agents also appear in `cinn
|
|
|
222
239
|
|
|
223
240
|
Detach a synced workspace: stop its sync session, revoke the minted CLI token server-side (via the account-scoped revoke endpoint, authenticated with the account token; idempotent), then perform the equivalent of `cinna disconnect`: remove `.cinna/`, generated files, and the registry entry. Workspace files under `agents/<slug>/workspace/` are preserved. The revoke degrades gracefully — if it fails (no connection, or a workspace synced before token-id tracking), a warning is printed and the local teardown still completes; the token then expires on its own or can be revoked from the agent's Integrations tab.
|
|
224
241
|
|
|
242
|
+
### `cinna agent import <path> [--name TEXT] [--workspace REF] [--update] [--dry-run] [--no-push] [--yes]`
|
|
243
|
+
|
|
244
|
+
Import an agent that was built **locally** with the [Local Agent Kit](docs/features/local_agent_import/local_agent_import.md) — a folder holding a `cinna-agent.json` manifest, typically `../Local/<slug>` next to this account workspace. Run it from the account workspace root (or any folder inside it).
|
|
245
|
+
|
|
246
|
+
Nine idempotent steps, each printed as `[n/9]`: read and validate the manifest → create (or resolve) the cloud agent → write its description, router trigger, example prompts and the three document prompts in one bulk write, plus the status refresh command → attach a local workspace (`cinna agent sync`) → copy the tree into `agents/<slug>/workspace/` honouring the contract's exclude list and secret rules, generating `workspace_requirements.txt` from `pyproject.toml` when the agent doesn't ship one → `cinna sync push` → create the credential drafts and attach them → create the schedules → record the publication in `publications.json` and print the summary.
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
cinna agent import ../Local/invoice-watcher --dry-run # see the plan, touch nothing
|
|
250
|
+
cinna agent import ../Local/invoice-watcher --yes
|
|
251
|
+
cinna chat --agent invoice-watcher "check invoices from last week"
|
|
252
|
+
|
|
253
|
+
# after more local work:
|
|
254
|
+
cinna agent import ../Local/invoice-watcher --update --yes
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
The folder rules come from the kit's versioned contract, `.cinna-kit/layout.json` — the same file Cinna Desktop reads — so a correction published there reaches this command on the next kit refresh rather than waiting for a new cinna-cli. `credentials/` and `app-data/` are **never** copied, not even if the contract drops them, and on top of the exclude list the contract's `secret_files` rules withhold every dotenv shape (`.env`, `.env.prod`, `staging.env`) wherever it sits, while `.env.example` still travels. No secret value is ever read, sent, or printed: credentials are created as empty drafts and the command prints the URLs the user opens to fill them in the browser.
|
|
258
|
+
|
|
259
|
+
Where the folder has been published is recorded in `publications.json`, a **sibling** of `cinna-agent.json` holding one entry per Cinna instance — it cannot live inside the manifest, because each entry records a hash of the exported tree and the manifest is part of that tree. Every step is idempotent (agent by the entry whose `platform_url` matches the instance you are logged into, credentials by name, schedules by name), so a partial import is resumed with `--update` instead of duplicating anything. The publication is recorded **only after the push settled** — `--no-push`, a failed flush, or remaining conflicts leave it unrecorded, and the next run is a plain `--update`. A legacy `cloud` block is migrated into the ledger on the first write and is still read until then, so an older folder's `--update` never creates a second agent. `--dry-run` makes no platform call and writes nothing.
|
|
260
|
+
|
|
225
261
|
### `cinna connect agent-api --producer <agent> --consumer <agent> [--label TEXT] [--read-only]`
|
|
226
262
|
|
|
227
263
|
Wire one agent to another's REST API from the account workspace. Resolves both agents (name, slug, or ID), mints a producer API token, and attaches it to the consumer as a credential — which rides the consumer's normal credential sync into its remote environment, so no key ever touches your machine. Prints the credential ID, token prefix, base URL, and spec URL. `--read-only` restricts the consumer to read-only access; `--label` names the credential. Backend errors surface verbatim: 400 if the producer's REST API is disabled, 403/404 for ownership violations.
|
|
@@ -137,6 +137,7 @@ Key properties:
|
|
|
137
137
|
A second token type (`token_type="cli-account"`) issued to an **account workspace** (`.cinna/account.json`). Scoped only to the `/account/*` routes — it discovers agents and mints per-agent CLI tokens (`cinna agent sync`), but cannot itself sync or exec. Same 7-day rolling expiry as a CLI token.
|
|
138
138
|
|
|
139
139
|
- **Refreshable without a paste** — `cinna login` runs an RFC 8628 device-authorization flow: the CLI prints a short code + URL, the user clicks **Authorize** in the browser (already signed in), and the CLI swaps the fresh token into `.cinna/account.json` in place. Run from an empty/new folder, the same command instead bootstraps a brand-new account workspace.
|
|
140
|
+
- **Refreshable from a setup token** — `cinna account set-token <token_or_url>` re-exchanges a fresh *account* setup token under the stored machine name and rewrites only `account_token` (same in-place swap). Bound to the same account: a different platform origin or token subject aborts with exit `11`. This is the path Cinna Desktop drives (`--no-input --json`) so the user never runs `cinna login`.
|
|
140
141
|
- **Mints child tokens** — per-agent tokens minted from it carry its id as provenance and are re-mintable via `POST /account/agents/{id}/mint` (used by `cinna agent sync` and `cinna doctor`).
|
|
141
142
|
|
|
142
143
|
### Knowledge Source
|
|
@@ -201,19 +202,24 @@ main.py (CLI commands — Click)
|
|
|
201
202
|
├── doctor.py — `cinna doctor`: reconcile registry ↔ Mutagen, delete stalled / terminate active sessions, refresh tokens
|
|
202
203
|
├── chat.py — `cinna chat`: session-backed conversation testing (poll + NDJSON) over the api-proxy
|
|
203
204
|
├── improve.py — `cinna improve`: improvement requests users shared about your agents (list/show/download/status)
|
|
205
|
+
├── local_import.py — `cinna agent import`: the Local Agent Kit go-cloud step
|
|
206
|
+
├── kit_contract.py — the Local Agent Kit contract as data (`.cinna-kit/layout.json`):
|
|
207
|
+
│ exclude patterns, secret-file rules, export walk, content_hash,
|
|
208
|
+
│ publications.json ledger, contract-version gate
|
|
204
209
|
├── config.py — .cinna/config.json: load/save/find
|
|
205
210
|
├── auth.py — JWT storage, Authorization headers
|
|
206
211
|
├── client.py — PlatformClient: HTTP + SSE stream_exec
|
|
207
|
-
├── mutagen_runtime.py — detect/install Mutagen; gate on version match
|
|
212
|
+
├── mutagen_runtime.py — detect/install Mutagen; gate on version match; `CINNA_MUTAGEN_BIN` override
|
|
213
|
+
├── cli_version.py — installed vs platform-pinned cinna-cli version
|
|
208
214
|
├── sync_session.py — wrap the `mutagen` CLI (start/stop/status/conflicts)
|
|
209
215
|
├── sync_tui.py — live Textual TUI shown by `cinna dev` (Sync/Details/Conflicts tabs)
|
|
210
216
|
├── sync_ssh_shim.py — `cinna-sync-ssh` entry point (WebSocket transport)
|
|
211
217
|
├── sync.py — tarball/zip extraction helpers (initial clone only)
|
|
212
218
|
├── context.py — CLAUDE.md, BUILDING_AGENT.md, .mcp.json, opencode.json
|
|
213
219
|
├── mcp_proxy.py — MCP stdio server for knowledge_query
|
|
214
|
-
├── console.py — Rich helpers
|
|
220
|
+
├── console.py — Rich helpers + the `--json` / `--no-input` switches (prompt/confirm wrappers, JSON lines)
|
|
215
221
|
├── logging.py — cinna.log (rotating file handler)
|
|
216
|
-
└── errors.py — exception hierarchy
|
|
222
|
+
└── errors.py — exception hierarchy; `CinnaExit` = stable exit code + machine code
|
|
217
223
|
```
|
|
218
224
|
|
|
219
225
|
### Local Directory Layout
|
|
@@ -278,8 +284,8 @@ authoring convention.
|
|
|
278
284
|
|
|
279
285
|
| Feature | Command surface | Docs |
|
|
280
286
|
|---|---|---|
|
|
281
|
-
| **Bootstrap & onboarding** | `cinna setup` / `set-token` / `login` / `list` / `status` / `disconnect[-all]` / `completion` / `dev` / `redev` | [business](features/bootstrap_onboarding/bootstrap_onboarding.md) · [tech](features/bootstrap_onboarding/bootstrap_onboarding_tech.md) · [acceptance](features/bootstrap_onboarding/bootstrap_onboarding_acceptance.md) |
|
|
282
|
-
| **Account workspace** | `cinna account` (setup, agents, status, refresh-context, user-workspace, credentials) | [business](features/account_workspace/account_workspace.md) · [tech](features/account_workspace/account_workspace_tech.md) · [acceptance](features/account_workspace/account_workspace_acceptance.md) |
|
|
287
|
+
| **Bootstrap & onboarding** | `cinna setup` / `set-token` / `login` / `list` / `status` / `disconnect[-all]` / `completion` / `dev` / `redev`; the no-TTY contract (`--no-input`, `--json`, exit codes, `CINNA_MUTAGEN_BIN`) | [business](features/bootstrap_onboarding/bootstrap_onboarding.md) · [tech](features/bootstrap_onboarding/bootstrap_onboarding_tech.md) · [acceptance](features/bootstrap_onboarding/bootstrap_onboarding_acceptance.md) |
|
|
288
|
+
| **Account workspace** | `cinna account` (setup, set-token, agents, status, refresh-context, user-workspace, credentials); desktop-managed workspaces | [business](features/account_workspace/account_workspace.md) · [tech](features/account_workspace/account_workspace_tech.md) · [acceptance](features/account_workspace/account_workspace_acceptance.md) |
|
|
283
289
|
| **Agent management** | `cinna agent` (sync, unsync, create, restart-env, show, status) | [business](features/agent_management/agent_management.md) · [tech](features/agent_management/agent_management_tech.md) · [acceptance](features/agent_management/agent_management_acceptance.md) |
|
|
284
290
|
| **Agent schedules** | `cinna agent schedule` (list, generate, create, update, run, logs, delete) | [business](features/agent_schedules/agent_schedules.md) · [tech](features/agent_schedules/agent_schedules_tech.md) · [acceptance](features/agent_schedules/agent_schedules_acceptance.md) |
|
|
285
291
|
| **Live sync** | `cinna sync` (status, conflicts, push, pull, resolve) + Mutagen transport | [business](features/live_sync/live_sync.md) · [tech](features/live_sync/live_sync_tech.md) · [acceptance](features/live_sync/live_sync_acceptance.md) |
|
|
@@ -289,6 +295,7 @@ authoring convention.
|
|
|
289
295
|
| **MCP integration** | `cinna connect mcp` · `cinna mcp-proxy` (knowledge stdio server) | [business](features/mcp_integration/mcp_integration.md) · [tech](features/mcp_integration/mcp_integration_tech.md) · [acceptance](features/mcp_integration/mcp_integration_acceptance.md) |
|
|
290
296
|
| **Git versioning** | `cinna git` (link, status, commit, push, pull, log, checkout, unlink) | [business](features/git_versioning/git_versioning.md) · [tech](features/git_versioning/git_versioning_tech.md) · [acceptance](features/git_versioning/git_versioning_acceptance.md) |
|
|
291
297
|
| **Improvement requests** | `cinna improve` (list, show, download, status) | [business](features/improvement_requests/improvement_requests.md) · [tech](features/improvement_requests/improvement_requests_tech.md) · [acceptance](features/improvement_requests/improvement_requests_acceptance.md) |
|
|
298
|
+
| **Local agent import** | `cinna agent import` (Local Agent Kit → cloud agent), incl. the versioned folder contract (`.cinna-kit/layout.json`), `publications.json` and `content_hash` | [business](features/local_agent_import/local_agent_import.md) · [tech](features/local_agent_import/local_agent_import_tech.md) · [acceptance](features/local_agent_import/local_agent_import_acceptance.md) |
|
|
292
299
|
|
|
293
300
|
The sections below (Git Versioning, Sync Transport, Remote Exec, Remote Chat,
|
|
294
301
|
Bootstrap Flow) remain as in-README quick references and backend contracts; the
|
|
@@ -600,6 +607,8 @@ When a CLI token expires (or is revoked) the normal remedy is `cinna set-token <
|
|
|
600
607
|
| Method | Route | Auth | Purpose |
|
|
601
608
|
|--------|-------|------|---------|
|
|
602
609
|
| POST | `/api/cli-setup/{token}` | Token | Exchange setup token for CLI token |
|
|
610
|
+
| POST | `/api/cli-setup/account/{token}` | Token | Exchange an **account** setup token (`cinna account setup` / `cinna account set-token`); 4xx ⇒ exit 10, 5xx ⇒ exit 12 |
|
|
611
|
+
| GET | `/.well-known/cinna-desktop` | None | Desktop discovery document; `local_dev.cinna_cli_version` is the cinna-cli pin `cinna account status` / `cinna doctor` compare against (absent ⇒ "unknown") |
|
|
603
612
|
| GET | `/api/v1/cli/agents/{id}/workspace` | CLI JWT | One-shot tarball for initial clone |
|
|
604
613
|
| GET | `/api/v1/cli/agents/{id}/building-context` | CLI JWT | Assembled building prompt |
|
|
605
614
|
| POST | `/api/v1/cli/agents/{id}/knowledge/search` | CLI JWT | Knowledge base search (via MCP proxy) |
|
|
@@ -640,6 +649,8 @@ uv run ruff format --check src/
|
|
|
640
649
|
|
|
641
650
|
The CLI is published to [PyPI](https://pypi.org/project/cinna-cli/) by `.github/workflows/publish.yml`, which runs on any pushed tag matching `v*` (and via manual `workflow_dispatch`). It builds the sdist + wheel with `uv build`, runs `twine check`, then publishes through PyPI **Trusted Publishing** (OIDC — no stored API token) from the GitHub `pypi` environment.
|
|
642
651
|
|
|
652
|
+
Cinna Desktop installs a **pinned** version (`uv tool install cinna-cli==<version>`) — the version each cinna-core instance advertises as `local_dev.cinna_cli_version` in its discovery document (`CINNA_CLI_VERSION` setting). A release that changes the driver contract (exit codes, `--json` shapes, the three desktop-driven verbs) must be published to PyPI **before** cinna-core's pin moves to it.
|
|
653
|
+
|
|
643
654
|
### Cutting a release
|
|
644
655
|
|
|
645
656
|
Versioning is SemVer (`MAJOR.MINOR.PATCH`); a patch release is the common case. From a clean `main` with the changes you want to ship already merged:
|
|
@@ -43,7 +43,16 @@ each with its own token, registry entry, and Mutagen session.
|
|
|
43
43
|
|
|
44
44
|
- **Account CLI token** — `cli-account` JWT in `.cinna/account.json`. Same 7-day
|
|
45
45
|
rolling expiry as a per-agent token. Refreshed in place by `cinna login` (a
|
|
46
|
-
browser device-authorization flow — no paste)
|
|
46
|
+
browser device-authorization flow — no paste) or by `cinna account set-token`
|
|
47
|
+
(paste / hand over a fresh account setup token). Mints child tokens; never
|
|
48
|
+
syncs.
|
|
49
|
+
- **Desktop-managed workspace** — an account workspace that Cinna Desktop
|
|
50
|
+
created and keeps alive by driving `cinna` as a child process with no
|
|
51
|
+
terminal: `account setup` once (into `<AgentsHome>/Cloud/<host>/`), then
|
|
52
|
+
`account set-token` whenever it mints a new setup token with its own
|
|
53
|
+
session, and `account status --json` to reconcile. The user never runs
|
|
54
|
+
`cinna login`, yet the workspace is byte-identical to a terminal-made one —
|
|
55
|
+
the user's own terminal can `cd` in and use every command.
|
|
47
56
|
- **`agents/` directory** — where `cinna agent sync` materializes per-agent
|
|
48
57
|
checkouts. Account commands that touch local state (`status`, `agents`,
|
|
49
58
|
`refresh-context`) walk this tree to find synced children.
|
|
@@ -74,11 +83,52 @@ each with its own token, registry entry, and Mutagen session.
|
|
|
74
83
|
`agents/`, the orchestrator `CLAUDE.md` + `.claude/settings.json`, the
|
|
75
84
|
knowledge MCP wiring, and the `context/` package. The folder name defaults to
|
|
76
85
|
the platform domain (e.g. `demo-core_opencinna_io`); `--dir` or the prompt
|
|
77
|
-
overrides it.
|
|
86
|
+
overrides it. `--dir` is a contract: an **absolute** path is used exactly as
|
|
87
|
+
given (missing parents are created), a relative one lands under the current
|
|
88
|
+
directory. Either way an existing `.cinna/account.json` at the target is
|
|
89
|
+
refused before the token is spent.
|
|
78
90
|
3. Alternatively, `cinna login <domain>` from an empty folder bootstraps the same
|
|
79
91
|
workspace via the browser device flow (no paste); run inside an existing
|
|
80
92
|
account workspace it refreshes the token in place.
|
|
81
93
|
|
|
94
|
+
### Refresh the token from a setup token — `cinna account set-token`
|
|
95
|
+
1. Mint a fresh **account** setup token (Settings → Local Development, or Cinna
|
|
96
|
+
Desktop does it with its own session).
|
|
97
|
+
2. Inside the account workspace, `cinna account set-token <token-or-url>`
|
|
98
|
+
re-exchanges it under the **stored** machine name and swaps only
|
|
99
|
+
`account_token` (plus a server-refreshed platform / frontend URL) into
|
|
100
|
+
`.cinna/account.json`. The active user workspace, machine name, `context/`
|
|
101
|
+
and every child under `agents/` are untouched — the same in-place contract
|
|
102
|
+
`cinna login` gives, minus the browser. A bare token reuses the stored
|
|
103
|
+
platform URL.
|
|
104
|
+
3. The new token must be for the **same account**: a different platform origin,
|
|
105
|
+
or a different `sub` on the token, is refused (exit 11) and nothing is written.
|
|
106
|
+
4. Child tokens are not touched; `cinna doctor` re-mints expired ones as usual.
|
|
107
|
+
|
|
108
|
+
### Driven by Cinna Desktop (no terminal)
|
|
109
|
+
1. The desktop obtains a setup token from the platform with its own session and
|
|
110
|
+
spawns `cinna account setup "<setup_command>" --dir <absolute> --name <machine>
|
|
111
|
+
--no-input --json`.
|
|
112
|
+
2. `--no-input` guarantees the process never waits for a human: every prompt
|
|
113
|
+
takes its default (machine name, folder), or fails with the machine code
|
|
114
|
+
`needs_input`. `CINNA_NO_INPUT=1` does the same for any command. `--json`
|
|
115
|
+
implies it.
|
|
116
|
+
3. `--json` turns the output into one JSON object per line on stdout: progress
|
|
117
|
+
lines `{step, total, status: start|ok|warn|fail, message}` mirroring the
|
|
118
|
+
numbered steps, then exactly one final line — `{"result": "ok", …}` with the
|
|
119
|
+
workspace path, platform / frontend URLs, machine name and context-package
|
|
120
|
+
outcome, or `{"result": "error", "code", "detail"}`. Nothing else touches
|
|
121
|
+
stdout; logs stay in `cinna.log`.
|
|
122
|
+
4. The process exit code is stable: `0` ok · `10` setup token invalid / expired /
|
|
123
|
+
already used · `11` the token is for another account · `12` the platform is
|
|
124
|
+
unreachable or answered 5xx · `1` anything else, with a specific `code`
|
|
125
|
+
(`workspace_exists`, `needs_input`, `mutagen_missing`, `mutagen_mismatch`,
|
|
126
|
+
`not_an_account_workspace`, …) · `2` bad invocation.
|
|
127
|
+
5. Later the desktop runs `cinna account set-token "<setup_command>" --no-input
|
|
128
|
+
--json` to refresh silently, and `cinna account status --json` to read token
|
|
129
|
+
validity, synced agents, context-package freshness and whether the installed
|
|
130
|
+
cinna-cli matches the version the platform pins.
|
|
131
|
+
|
|
82
132
|
### Discover and attach agents
|
|
83
133
|
1. `cinna account agents` lists the agents the account can access — name + id,
|
|
84
134
|
build rights (foreign bundle installs are view-only), whether the remote env
|
|
@@ -126,7 +176,25 @@ each with its own token, registry entry, and Mutagen session.
|
|
|
126
176
|
sync/exec always use the per-agent child token via the per-agent client.
|
|
127
177
|
- **Single-use setup token is guarded before it's burned.** `cinna account setup`
|
|
128
178
|
refuses an existing-workspace target *before* exchanging the token, so a doomed
|
|
129
|
-
run never wastes the one-time token.
|
|
179
|
+
run never wastes the one-time token (exit 1, code `workspace_exists`).
|
|
180
|
+
- **`set-token` is account-bound, fail-loud.** The refreshed token must match
|
|
181
|
+
the workspace's platform origin and (when both tokens carry one) the same
|
|
182
|
+
subject; otherwise nothing is written and the command exits 11
|
|
183
|
+
(`account_mismatch`). It never rebinds a workspace to another account.
|
|
184
|
+
- **Never hang without a terminal.** Under `--no-input` (or `CINNA_NO_INPUT=1`,
|
|
185
|
+
or `--json`) no command blocks on stdin: prompts take their default or fail
|
|
186
|
+
with `needs_input`; confirmations take their default (usually "No", which
|
|
187
|
+
aborts). The `/dev/tty` fallback the `curl | python3` bootstrap uses for the
|
|
188
|
+
folder prompt is skipped too.
|
|
189
|
+
- **`--json` is a pure stream.** Rich output is suppressed entirely; each stdout
|
|
190
|
+
line is one JSON object and the last one is always the `result` line, on
|
|
191
|
+
success and on failure alike. Human output is unchanged when the flag is off.
|
|
192
|
+
- **Exit codes are a contract.** 0 / 10 / 11 / 12 / 1 (+ `code`) / 2 as listed
|
|
193
|
+
in the desktop flow; every error the CLI raises on purpose maps onto it, so a
|
|
194
|
+
driver switches on the number, not on message text.
|
|
195
|
+
- **Version pin is advisory.** `account status` compares the running cinna-cli
|
|
196
|
+
with the version the platform publishes in its discovery document; a missing
|
|
197
|
+
pin is `unknown`, never an error.
|
|
130
198
|
- **Fail-loud on backend errors.** Token exchange, mint, and every account call
|
|
131
199
|
surface the backend's `detail` verbatim (expired/used token, foreign-install
|
|
132
200
|
403, ambiguous agent). The CLI does not pre-judge build rights client-side —
|
|
@@ -173,7 +241,11 @@ cinna account setup ────────────────────
|
|
|
173
241
|
▼
|
|
174
242
|
.cinna/account.json (account CLI token, cli-account scope)
|
|
175
243
|
│
|
|
244
|
+
├── cinna account set-token <token> ───────────────────► POST /cli-setup/account/<token>
|
|
245
|
+
│ (stored machine name; same-account check; rewrites account_token only)
|
|
246
|
+
├── cinna login (device flow) ─────────────────────────► /api/v1/cli/account/login/*
|
|
176
247
|
├── cinna account agents / status / refresh-context ─► AccountClient ─► /api/v1/cli/account/*
|
|
248
|
+
│ (status: + GET /.well-known/cinna-desktop for the cinna-cli pin)
|
|
177
249
|
├── cinna account user-workspace … (client-side active selection)
|
|
178
250
|
├── cinna account credentials … (metadata-only drafts)
|
|
179
251
|
│
|
|
@@ -205,11 +277,17 @@ cinna account setup ────────────────────
|
|
|
205
277
|
publisher-install flag its ownership step depends on. See
|
|
206
278
|
[improvement_requests](../improvement_requests/improvement_requests.md).
|
|
207
279
|
- **Doctor / login** — `cinna doctor` re-mints expired per-agent tokens through
|
|
208
|
-
the account token, and groups blocked agents under a single `cinna login`
|
|
209
|
-
when the account token itself has expired.
|
|
280
|
+
the account token, and groups blocked agents under a single `cinna login` /
|
|
281
|
+
`cinna account set-token` hint when the account token itself has expired. It
|
|
282
|
+
also reports a cinna-cli that differs from the platform's pin.
|
|
283
|
+
- **Bootstrap / onboarding** — the no-terminal contract (`--no-input`, `--json`,
|
|
284
|
+
exit codes, `CINNA_MUTAGEN_BIN`) is CLI-wide and described in
|
|
285
|
+
[Bootstrap & Onboarding](../bootstrap_onboarding/bootstrap_onboarding.md);
|
|
286
|
+
this doc covers how the account verbs use it.
|
|
287
|
+
- **Cinna Desktop** — installs its own pinned cinna-cli (with uv and Mutagen) and
|
|
288
|
+
drives the three verbs above; the desktop-side plan lives in the cinna-desktop
|
|
289
|
+
repo (`plans/one-click-onboarding-desktop.md`). <!-- nocheck: cross-repo path -->
|
|
210
290
|
|
|
211
291
|
Implementation: see [account_workspace_tech.md](account_workspace_tech.md).
|
|
212
292
|
Real-usage e2e test scenarios: see
|
|
213
293
|
[account_workspace_acceptance.md](account_workspace_acceptance.md).
|
|
214
|
-
</content>
|
|
215
|
-
</invoke>
|
{cinna_cli-0.2.6 → cinna_cli-0.4.0}/docs/features/account_workspace/account_workspace_acceptance.md
RENAMED
|
@@ -26,8 +26,10 @@ the silent-secret and scope-drift bugs live.
|
|
|
26
26
|
- **Editable install** of the CLI under test:
|
|
27
27
|
`python3 -c "import cinna,os;print(os.path.dirname(cinna.__file__))"` must point
|
|
28
28
|
at this repo's `src/cinna`. Confirm `which cinna` resolves and
|
|
29
|
-
`cinna account --help` lists `setup /
|
|
30
|
-
user-workspace / credentials`.
|
|
29
|
+
`cinna account --help` lists `setup / set-token / agents / status /
|
|
30
|
+
refresh-context / user-workspace / credentials`.
|
|
31
|
+
- For the no-terminal scenarios (15–18): `jq` to inspect the JSON lines, and a
|
|
32
|
+
second **account** setup token per run (every exchange burns one).
|
|
31
33
|
- `git` and `mutagen` on `PATH` (needed once a child agent is synced and
|
|
32
34
|
exercised).
|
|
33
35
|
|
|
@@ -253,8 +255,114 @@ the silent-secret and scope-drift bugs live.
|
|
|
253
255
|
- **Watch for:** user files deleted; the registry entry surviving; a revoke error
|
|
254
256
|
aborting the command.
|
|
255
257
|
|
|
258
|
+
### 15. Desktop-style setup: absolute `--dir`, `--no-input`, `--json`, no TTY
|
|
259
|
+
|
|
260
|
+
- **Goal:** Cinna Desktop creates the account workspace as a child process with
|
|
261
|
+
no terminal and parses the result.
|
|
262
|
+
- **Setup:** a fresh account setup token; note the `setup_command` string the
|
|
263
|
+
platform returns (`curl -sL …/api/cli-setup/account/<TOKEN> | python3 -`).
|
|
264
|
+
- **Steps:**
|
|
265
|
+
```
|
|
266
|
+
TARGET="$HOME/CinnaAgents/Cloud/localhost" # parents must not exist yet
|
|
267
|
+
cinna account setup 'curl -sL http://localhost:8000/api/cli-setup/account/<TOKEN> | python3 -' \
|
|
268
|
+
--dir "$TARGET" --name desktop-test --no-input --json < /dev/null > out.jsonl; echo "exit $?"
|
|
269
|
+
cat out.jsonl | jq -c .
|
|
270
|
+
ls -a "$TARGET"; cat "$TARGET/.cinna/account.json"
|
|
271
|
+
```
|
|
272
|
+
- **Expected:** exit `0`. Every line of `out.jsonl` parses; the first three are
|
|
273
|
+
`{"step":1..3,"total":3,"status":"start",…}`, the last is `{"result":"ok",
|
|
274
|
+
"workspace":"<TARGET>","platform_url":…,"frontend_url":…,"machine_name":
|
|
275
|
+
"desktop-test","context_package":"ok"}`. The workspace sits exactly at
|
|
276
|
+
`$TARGET` (dots in the host kept, parents created), with the same files as
|
|
277
|
+
scenario 1. No table, hint or spinner text on stdout.
|
|
278
|
+
- **Watch for:** the workspace landing under cwd instead of the absolute path;
|
|
279
|
+
a non-JSON line on stdout (Rich leaking); the process waiting on stdin
|
|
280
|
+
(folder / machine-name prompt); `context_package` not reflecting a failed
|
|
281
|
+
download (should be `failed` with a preceding `"status":"warn"` line, exit
|
|
282
|
+
still 0).
|
|
283
|
+
|
|
284
|
+
### 16. Desktop-style refresh: `account set-token` in place, same account only
|
|
285
|
+
|
|
286
|
+
- **Goal:** the desktop refreshes an expiring account token silently; a token
|
|
287
|
+
for another account can never be swapped in.
|
|
288
|
+
- **Setup:** scenario 15's workspace; `cinna account user-workspace activate
|
|
289
|
+
<name>` so a client-side selection exists; one synced child (scenario 5).
|
|
290
|
+
Mint two fresh account setup tokens: one as the **same** user, one as a
|
|
291
|
+
**different** user on the same platform.
|
|
292
|
+
- **Steps:**
|
|
293
|
+
```
|
|
294
|
+
cd "$TARGET"; cp .cinna/account.json /tmp/before.json
|
|
295
|
+
cinna account set-token 'curl -sL http://localhost:8000/api/cli-setup/account/<SAME_USER_TOKEN> | python3 -' \
|
|
296
|
+
--no-input --json < /dev/null; echo "exit $?"
|
|
297
|
+
diff <(jq 'del(.account_token)' /tmp/before.json) <(jq 'del(.account_token)' .cinna/account.json)
|
|
298
|
+
cat agents/<slug>/.cinna/config.json | jq .cli_token # unchanged
|
|
299
|
+
cinna account set-token 'curl -sL http://localhost:8000/api/cli-setup/account/<OTHER_USER_TOKEN> | python3 -' \
|
|
300
|
+
--no-input --json < /dev/null; echo "exit $?"
|
|
301
|
+
cinna account set-token '<SAME_USER_TOKEN again>' --json; echo "exit $?"
|
|
302
|
+
```
|
|
303
|
+
- **Expected:** first call exits `0`, prints two `start` steps, an `ok` line
|
|
304
|
+
and `{"result":"ok",…,"context_package":"skipped"}`; only `account_token`
|
|
305
|
+
changed (the `diff` is empty), the child token is untouched, and the exchange
|
|
306
|
+
was made with the **stored** machine name (check the CLI token list in
|
|
307
|
+
Settings — no new machine). The other-user call exits `11` with
|
|
308
|
+
`{"result":"error","code":"account_mismatch",…}` and `account.json` is
|
|
309
|
+
unchanged. The reused (already burned) token exits `10` with
|
|
310
|
+
`code: "setup_token_invalid"` and the backend detail.
|
|
311
|
+
- **Watch for:** the mismatch being detected only after the file was written;
|
|
312
|
+
`user_workspace_id` or `machine_name` reset; a new machine appearing in the
|
|
313
|
+
platform's token list; exit `1` where `10` / `11` is required.
|
|
314
|
+
|
|
315
|
+
### 17. Exit-code contract
|
|
316
|
+
|
|
317
|
+
- **Goal:** a driver can act on the exit code alone.
|
|
318
|
+
- **Steps:** run each from a scratch dir with `--no-input --json < /dev/null`
|
|
319
|
+
and record `$?` plus the final line's `code`:
|
|
320
|
+
```
|
|
321
|
+
cinna account setup '<ALREADY_USED_TOKEN_URL>' --dir /tmp/x1 # 10 setup_token_invalid
|
|
322
|
+
cinna account setup '<VALID_URL>' --dir "$TARGET" # 1 workspace_exists (token NOT burned)
|
|
323
|
+
cinna account setup 'http://127.0.0.1:1/api/cli-setup/account/X' --dir /tmp/x2 # 12 network
|
|
324
|
+
cinna account status # 1 not_an_account_workspace
|
|
325
|
+
cinna --no-input login # 1 needs_input (no domain, human text)
|
|
326
|
+
cinna account setup # 2 usage
|
|
327
|
+
```
|
|
328
|
+
Then, with the backend stopped: `cinna account set-token '<URL>' --json` → `12`.
|
|
329
|
+
- **Expected:** the codes in the comments. For the `workspace_exists` case,
|
|
330
|
+
re-use the same valid token afterwards in a fresh dir — it must still work.
|
|
331
|
+
- **Watch for:** any of these coming back as a bare `1`; a traceback instead of
|
|
332
|
+
a JSON error line; the guard case burning the token.
|
|
333
|
+
|
|
334
|
+
### 18. `account status --json` and the cinna-cli version pin
|
|
335
|
+
|
|
336
|
+
- **Goal:** the desktop reconciles from one status line, including whether to
|
|
337
|
+
reinstall cinna-cli.
|
|
338
|
+
- **Steps:**
|
|
339
|
+
```
|
|
340
|
+
cd "$TARGET"; cinna account status --json | jq .
|
|
341
|
+
curl -s http://localhost:8000/.well-known/cinna-desktop | jq .local_dev
|
|
342
|
+
cinna account status | tail -20
|
|
343
|
+
cinna doctor --dry-run
|
|
344
|
+
```
|
|
345
|
+
- **Expected:** exactly one JSON line with `result`, `workspace`,
|
|
346
|
+
`platform_url`, `frontend_url`, `machine_name`, `active_workspace`
|
|
347
|
+
(`{id,name}` or `null`), `token` (`valid|expired|unreachable`),
|
|
348
|
+
`synced_agents`, `agents[]`, `context_package{local,remote,state}` and
|
|
349
|
+
`cli{installed,required,state}`. When the platform publishes
|
|
350
|
+
`local_dev.cinna_cli_version`, `cli.required` equals it and `state` is
|
|
351
|
+
`current` / `behind` / `ahead`; on an older platform `required` is `null`
|
|
352
|
+
and `state` is `unknown` — still exit 0. The human `status` shows the same
|
|
353
|
+
as a `cinna-cli` table row and a `uv tool install cinna-cli==<pin>` hint when
|
|
354
|
+
behind; `doctor` lists the platform under "manual action needed" only when
|
|
355
|
+
the pin differs.
|
|
356
|
+
- **Watch for:** a missing discovery document turning into an error; `doctor`
|
|
357
|
+
nagging when no pin is published; the JSON line missing `cli`.
|
|
358
|
+
|
|
256
359
|
## Cross-cutting invariants (must hold across all scenarios)
|
|
257
360
|
|
|
361
|
+
- **`--json` stdout is JSON only, last line is the verdict** — every stdout line
|
|
362
|
+
parses; exactly one `result` line; human hints never leak.
|
|
363
|
+
- **Never wait for a human without a terminal** — with `--no-input` / `--json`
|
|
364
|
+
/ `CINNA_NO_INPUT=1` every command either proceeds or fails with
|
|
365
|
+
`needs_input`; nothing reads stdin or `/dev/tty`.
|
|
258
366
|
- **No secret ever sent** — credential create/update bodies carry only metadata;
|
|
259
367
|
the CLI cannot read or write a credential's secret value.
|
|
260
368
|
- **Account token stays account-scoped** — it is used only on `/account/*`; every
|
|
@@ -284,4 +392,3 @@ the silent-secret and scope-drift bugs live.
|
|
|
284
392
|
- Verify `~/.cinna/agents.json` has no leftover entries for the test children —
|
|
285
393
|
especially if any helper ran **outside** pytest's global-state isolation (it
|
|
286
394
|
would write the real registry).
|
|
287
|
-
</content>
|