cinna-cli 0.4.3__tar.gz → 0.5.1__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.4.3 → cinna_cli-0.5.1}/PKG-INFO +3 -1
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/README.md +2 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/delegation/delegation.md +5 -3
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/delegation/delegation_tech.md +3 -2
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/local_agent_import/local_agent_import.md +42 -6
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/local_agent_import/local_agent_import_acceptance.md +45 -3
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/local_agent_import/local_agent_import_tech.md +103 -6
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/pyproject.toml +1 -1
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/client.py +9 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/delegation.py +11 -5
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/kit_contract.py +7 -2
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/local_import.py +111 -1
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/tests/test_client.py +15 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/tests/test_delegation.py +10 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/tests/test_local_import.py +327 -5
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/uv.lock +1 -1
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/.claude/commands/cinna-cli.feature.doc.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/.github/workflows/publish.yml +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/.gitignore +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/LICENSE.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/README.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/account_workspace/account_workspace.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/account_workspace/account_workspace_acceptance.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/account_workspace/account_workspace_tech.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/agent_addons/agent_addons.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/agent_addons/agent_addons_acceptance.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/agent_addons/agent_addons_tech.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/agent_api/agent_api.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/agent_api/agent_api_acceptance.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/agent_api/agent_api_tech.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/agent_management/agent_management.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/agent_management/agent_management_acceptance.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/agent_management/agent_management_tech.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/agent_schedules/agent_schedules.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/agent_schedules/agent_schedules_acceptance.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/agent_schedules/agent_schedules_tech.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/bootstrap_onboarding/bootstrap_onboarding.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/bootstrap_onboarding/bootstrap_onboarding_acceptance.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/bootstrap_onboarding/bootstrap_onboarding_tech.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/delegation/delegation_acceptance.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/doctor/doctor.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/doctor/doctor_acceptance.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/doctor/doctor_tech.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/git_versioning/git_versioning.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/git_versioning/git_versioning_acceptance.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/git_versioning/git_versioning_tech.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/improvement_requests/improvement_requests.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/improvement_requests/improvement_requests_acceptance.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/improvement_requests/improvement_requests_tech.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/live_sync/live_sync.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/live_sync/live_sync_acceptance.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/live_sync/live_sync_tech.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/mcp_integration/mcp_integration.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/mcp_integration/mcp_integration_acceptance.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/mcp_integration/mcp_integration_tech.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/remote_chat/remote_chat.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/remote_chat/remote_chat_acceptance.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/remote_chat/remote_chat_tech.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/remote_exec/remote_exec.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/remote_exec/remote_exec_acceptance.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/remote_exec/remote_exec_tech.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/interface.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/mutagen_capabilities.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/scripts/check_docs_references.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/__init__.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/account.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/auth.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/bootstrap.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/chat.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/cli_version.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/config.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/console.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/context.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/doctor.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/errors.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/git_versioning.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/improve.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/logging.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/main.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/mcp_proxy.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/mutagen_runtime.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/scenarios.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/sync.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/sync_session.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/sync_ssh_shim.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/sync_tui.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/templates/ACCOUNT_CLAUDE.md.template +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/templates/CHAT_TESTING.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/templates/CLAUDE.md.template +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/templates/GIT_VERSIONING.md +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/src/cinna/templates/__init__.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/tests/__init__.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/tests/conftest.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/tests/test_account.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/tests/test_auth.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/tests/test_bootstrap.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/tests/test_chat.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/tests/test_cli_version.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/tests/test_config.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/tests/test_console.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/tests/test_context.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/tests/test_doctor.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/tests/test_git_versioning.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/tests/test_improve.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/tests/test_kit_contract.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/tests/test_main.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/tests/test_mutagen_runtime.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/tests/test_onboarding.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/tests/test_scenarios.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/tests/test_sync.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/tests/test_sync_session.py +0 -0
- {cinna_cli-0.4.3 → cinna_cli-0.5.1}/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.5.1
|
|
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
|
|
@@ -338,6 +338,8 @@ The folder rules come from the kit's versioned contract, `.cinna-kit/layout.json
|
|
|
338
338
|
|
|
339
339
|
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.
|
|
340
340
|
|
|
341
|
+
The manifest's `runtime.engine` (`opencode`, `claude`, `codex`, …) is sent when the agent is **created**; the platform runs an engine it does not support on OpenCode, and `--update` never changes an existing agent's engine. The plan prints an `Engine:` line, and a `Not carried to the cloud:` line naming the manifest fields present that the cloud has no place for (`runtime.model`, `runtime.complexity`, `runtime.credential`, `runtime.permissions`, unknown `runtime.*` keys, `handovers` — the import sends no handover at all — and `capabilities`). A malformed `runtime` costs a warning, never the import.
|
|
342
|
+
|
|
341
343
|
### `cinna skills list <agent> [--json]`
|
|
342
344
|
|
|
343
345
|
List everything an agent carries beyond its prompt, as one deduplicated list. An **addon** is either an installed plugin or a `skills/<name>/` folder — a `SKILL.md` plus its files that the engine loads on demand. The two overlap (a skill installed from the catalog is *also* a plugin link), and the platform owns the dedupe rule, so this prints the server's projection rather than folding the halves itself: one row per addon, with its kind, source (`marketplace` / `bundle` / `catalog` / `local`), status, name and version.
|
|
@@ -301,6 +301,8 @@ The folder rules come from the kit's versioned contract, `.cinna-kit/layout.json
|
|
|
301
301
|
|
|
302
302
|
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.
|
|
303
303
|
|
|
304
|
+
The manifest's `runtime.engine` (`opencode`, `claude`, `codex`, …) is sent when the agent is **created**; the platform runs an engine it does not support on OpenCode, and `--update` never changes an existing agent's engine. The plan prints an `Engine:` line, and a `Not carried to the cloud:` line naming the manifest fields present that the cloud has no place for (`runtime.model`, `runtime.complexity`, `runtime.credential`, `runtime.permissions`, unknown `runtime.*` keys, `handovers` — the import sends no handover at all — and `capabilities`). A malformed `runtime` costs a warning, never the import.
|
|
305
|
+
|
|
304
306
|
### `cinna skills list <agent> [--json]`
|
|
305
307
|
|
|
306
308
|
List everything an agent carries beyond its prompt, as one deduplicated list. An **addon** is either an installed plugin or a `skills/<name>/` folder — a `SKILL.md` plus its files that the engine loads on demand. The two overlap (a skill installed from the catalog is *also* a plugin link), and the platform owns the dedupe rule, so this prints the server's projection rather than folding the halves itself: one row per addon, with its kind, source (`marketplace` / `bundle` / `catalog` / `local`), status, name and version.
|
|
@@ -152,9 +152,11 @@ result attached to the current task ──► delivered to the requester (Deskto
|
|
|
152
152
|
- **Remote chat** — a delegated task runs as a platform session like the ones
|
|
153
153
|
`cinna chat` drives. See [Remote Chat](../remote_chat/remote_chat.md).
|
|
154
154
|
- **cinna-core task MCP server (not in this repo)** — inside cloud tasks the
|
|
155
|
-
backend's MCP
|
|
156
|
-
|
|
157
|
-
|
|
155
|
+
backend's `cinna` MCP server exposes a `tasks_report` tool (the Cinna Task
|
|
156
|
+
Protocol, kit contract 1.6.0) that records the same kind of result; an
|
|
157
|
+
environment built before protocol version 1 still has it as `handover_report`
|
|
158
|
+
on the older `agent_task` server. It is implemented and documented in
|
|
159
|
+
cinna-core; this CLI only offers the equivalent command-line path.
|
|
158
160
|
|
|
159
161
|
Implementation: see [delegation_tech.md](delegation_tech.md).
|
|
160
162
|
Real-usage e2e scenarios: see [delegation_acceptance.md](delegation_acceptance.md).
|
|
@@ -122,8 +122,9 @@ Executor side — direct call, agent-token auth:
|
|
|
122
122
|
belongs to this environment's agent and owner, and resolves the task from the
|
|
123
123
|
session. Any 2xx is success.
|
|
124
124
|
|
|
125
|
-
Related, not in this repo: cinna-core's
|
|
126
|
-
`
|
|
125
|
+
Related, not in this repo: cinna-core's `cinna` MCP server exposes a
|
|
126
|
+
`tasks_report` tool for the same executor-side report (`handover_report` on
|
|
127
|
+
environments built before protocol version 1).
|
|
127
128
|
|
|
128
129
|
## Edge cases & guardrails (preserve these)
|
|
129
130
|
|
|
@@ -21,7 +21,9 @@ The kit's machine-readable half is a **versioned contract** (`layout.json`,
|
|
|
21
21
|
`GET /api/agent-start/contract.tar.gz` with a cheap version poll at
|
|
22
22
|
`GET /api/agent-start/contract/version`. cinna-cli reads the copy installed at
|
|
23
23
|
`.cinna-kit/`; a shipped build should obtain it from those routes rather than
|
|
24
|
-
vendoring one.
|
|
24
|
+
vendoring one. This build implements contract **1.5.0** (`runtime.engine`,
|
|
25
|
+
`runtime.complexity` and `handovers[].target_kind` in core's one schema); only
|
|
26
|
+
the major decides compatibility, so any `1.x` folder imports.
|
|
25
27
|
|
|
26
28
|
Nothing platform-side is new: the import replays the manifest through the
|
|
27
29
|
existing account-scoped verbs (`agent create`, the bulk prompt write, `agent
|
|
@@ -57,6 +59,30 @@ sync`, `sync push`, `account credentials create`, `agent schedule create`,
|
|
|
57
59
|
`.env.sample` and `.env.template` still travel. Credentials are created as
|
|
58
60
|
**empty drafts** and the command prints the URLs the user opens to fill each
|
|
59
61
|
one in the browser. No secret value is read, sent, or printed at any point.
|
|
62
|
+
- **A credential spec can name its slot.** Since contract 1.4.0 a manifest
|
|
63
|
+
credential may carry `service_uri` — the slot the agent's credential reader
|
|
64
|
+
matches an attached credential on. The import passes it to the draft
|
|
65
|
+
unchanged; one that is not a non-empty string is refused with the other
|
|
66
|
+
manifest guards, before the agent is created.
|
|
67
|
+
- **The engine is a preference, carried once.** A manifest's `runtime.engine`
|
|
68
|
+
(`opencode`, `claude`, `codex`, or a name this build has never heard of) is
|
|
69
|
+
sent to the platform when the agent is **created**, which maps it to the
|
|
70
|
+
environment's SDK and runs an engine it does not support on OpenCode — the
|
|
71
|
+
folder is never refused over it. `--update` never changes an existing agent's
|
|
72
|
+
engine. A `runtime` that is not an object, or an engine that is not a string,
|
|
73
|
+
costs a warning and nothing is sent.
|
|
74
|
+
- **What the cloud does not carry is named, not dropped silently.** The other
|
|
75
|
+
`runtime` fields (`model`, `complexity`, `credential`, `permissions`, and any
|
|
76
|
+
key this build does not know) have no cloud counterpart, and the import
|
|
77
|
+
sends no `handovers` at all (not only the desktop's `target_kind`) and maps
|
|
78
|
+
`capabilities` onto nothing; the plan lists the ones present in one
|
|
79
|
+
`Not carried to the cloud:` line.
|
|
80
|
+
- **Using cloud credentials on the desktop is not an import concern.** A
|
|
81
|
+
locally running agent in Cinna Desktop gets credential values from the
|
|
82
|
+
platform's desktop delivery route, gated per credential by *allow local use*
|
|
83
|
+
for credentials shared with you (your own always qualify). That exchange is
|
|
84
|
+
between the platform and the desktop; `cinna agent import` never reads
|
|
85
|
+
credential values, and the CLI has no switch for *allow local use* yet.
|
|
60
86
|
- **The ledger is a sibling file, never a manifest key.** Where an agent folder
|
|
61
87
|
has been published is recorded in `publications.json` beside
|
|
62
88
|
`cinna-agent.json` — one entry per Cinna instance. It has to be a separate
|
|
@@ -83,10 +109,11 @@ Each prints as `[n/9]`:
|
|
|
83
109
|
contract: refuse a folder built against a newer **major** contract version,
|
|
84
110
|
warn on an older one or on a folder that records none, resolve the exclude
|
|
85
111
|
list and the secret rules, plan the copy and compute the tree's
|
|
86
|
-
`content_hash`.
|
|
112
|
+
`content_hash`. Read `runtime` tolerantly and print the `Engine:` line and,
|
|
113
|
+
when any are present, the `Not carried to the cloud:` line.
|
|
87
114
|
2. **Agent** — resolve by the `publications.json` entry for this instance
|
|
88
115
|
(requires `--update`) or create a new agent in the active user workspace
|
|
89
|
-
(`--workspace` overrides).
|
|
116
|
+
(`--workspace` overrides), passing `runtime.engine` on creation only.
|
|
90
117
|
3. **Prompts + metadata** — one bulk write carrying `description`,
|
|
91
118
|
`router_trigger_prompt`, `example_prompts`, and the three document prompts
|
|
92
119
|
read from the files named in `prompts`; then the status refresh command.
|
|
@@ -99,7 +126,8 @@ Each prints as `[n/9]`:
|
|
|
99
126
|
6. **Push** — `cinna sync push` equivalent (skipped by `--no-push`).
|
|
100
127
|
7. **Credentials** — one empty draft per spec, attached to the agent; an
|
|
101
128
|
existing credential of the same name is attached rather than recreated.
|
|
102
|
-
|
|
129
|
+
A spec's `service_uri` is set on a new draft; an existing credential keeps
|
|
130
|
+
its own. Setup URLs are collected for the summary.
|
|
103
131
|
8. **Schedules** — one per spec, name-idempotent; `--update` rewrites an
|
|
104
132
|
existing schedule in place.
|
|
105
133
|
9. **Record** — add or update this instance's entry in `publications.json`
|
|
@@ -131,7 +159,11 @@ file that would be copied, every credential draft, every schedule — and makes
|
|
|
131
159
|
`publications.json` entry whose `platform_url` matches the instance you are
|
|
132
160
|
logged into (not by workspace, and not by position in the list), rewrites
|
|
133
161
|
prompts and metadata, re-copies the tree, pushes, attaches existing credentials,
|
|
134
|
-
and updates the schedules in place.
|
|
162
|
+
and updates the schedules in place. The agent's engine is left as it is; when
|
|
163
|
+
the manifest names one, the `Engine:` line says it was not applied. An
|
|
164
|
+
`--update` with no known agent id cannot tell from the plan whether it will
|
|
165
|
+
find the agent by name or create it, so the plan says the engine is sent only
|
|
166
|
+
on creation, and the lookup then says which happened.
|
|
135
167
|
|
|
136
168
|
### Resume a partial import
|
|
137
169
|
|
|
@@ -160,11 +192,15 @@ created are reused, not duplicated.
|
|
|
160
192
|
| `schema_version` newer than supported | Refused with an upgrade hint — never half-read |
|
|
161
193
|
| Folder built against a newer **major** contract version | Refused with an upgrade hint — a minor or patch difference is not a compatibility question and passes silently |
|
|
162
194
|
| Folder records no `contract_version` | Warned and imported — every folder created before contract 1.0.0 is in that state |
|
|
195
|
+
| A credential's `service_uri` is empty or not a string | Refused before any platform call, naming the credential |
|
|
196
|
+
| `runtime` is not an object, or `runtime.engine` is not a string | Warned and imported; no engine is sent, so the agent gets the platform default |
|
|
197
|
+
| `runtime.engine` names an engine the cloud does not support | Imported; the platform runs the agent on OpenCode |
|
|
198
|
+
| Older platform without the `engine` create field | Imported; the platform ignores the unknown field and the agent gets its default engine |
|
|
163
199
|
| Already imported to this instance, no `--update` | Refused, naming the agent id and where the link was recorded |
|
|
164
200
|
| The recorded agent id is not among your agents | Refused — you are logged into a different platform, or the agent was deleted |
|
|
165
201
|
| `--update` with several name matches | Refused, listing them; add the `publications.json` entry to disambiguate |
|
|
166
202
|
| Push failed or left conflicts | Warned, **nothing recorded**, with the resolve + `--update` hint |
|
|
167
|
-
| `.cinna-kit/layout.json` missing or unreadable | Imported with the built-in contract
|
|
203
|
+
| `.cinna-kit/layout.json` missing or unreadable | Imported with the built-in copy of contract 1.5.0, the `Exclusions:` line marked `DEGRADED`, and **no `content_hash` recorded** — a hash over a file set another host would not select is worse than none |
|
|
168
204
|
| A travelling file or directory cannot be read | Refused — a complete-looking export with a subtree missing from it is the one outcome worth stopping for |
|
|
169
205
|
| `publications.json` unreadable | Refused, and the file is left exactly as it was |
|
|
170
206
|
| Credential/schedule 403 | The platform error surfaces verbatim; earlier steps stay done and `--update` resumes |
|
|
@@ -121,7 +121,8 @@ any change to the orchestrator.
|
|
|
121
121
|
|
|
122
122
|
- **Steps:** in a scratch copy of the agent folder, one at a time: bump
|
|
123
123
|
`schema_version` to `2`; rename the folder so it disagrees with `slug`; make
|
|
124
|
-
`cron_string` `"every morning"`; drop a credential's `type
|
|
124
|
+
`cron_string` `"every morning"`; drop a credential's `type`; set a
|
|
125
|
+
credential's `service_uri` to `""`.
|
|
125
126
|
- **Expected:** each is refused *before* any platform call, with a message that
|
|
126
127
|
names the offending field.
|
|
127
128
|
- **Watch for:** a half-applied import (agent created, then the manifest
|
|
@@ -242,14 +243,55 @@ any change to the orchestrator.
|
|
|
242
243
|
### 10f. The `contract_version` gate
|
|
243
244
|
|
|
244
245
|
- **Steps:** set the manifest's `contract_version` to `2.0.0` and import; then
|
|
245
|
-
to `1.
|
|
246
|
+
to `1.5.2` and import; then remove the key entirely and import.
|
|
246
247
|
- **Expected:** `2.0.0` is refused before any platform call, naming `2.x`;
|
|
247
|
-
`1.
|
|
248
|
+
`1.5.2` passes **silently** (same major — a minor contract change is additive
|
|
248
249
|
by definition and reaches a non-adopting reader as silence); the missing key
|
|
249
250
|
warns about a re-stamp and imports anyway.
|
|
250
251
|
- **Watch for:** a warning on the same-major pair. That is the gate's shape, not
|
|
251
252
|
a bug: anything an old reader must notice needs a major bump.
|
|
252
253
|
|
|
254
|
+
### 10g. A credential slot reaches the draft (contract 1.4.0)
|
|
255
|
+
|
|
256
|
+
- **Goal:** a manifest credential that names its slot gets a draft the agent's
|
|
257
|
+
credential reader can match, in the cloud and on the desktop.
|
|
258
|
+
- **Setup:** a fresh agent whose manifest credential carries
|
|
259
|
+
`"service_uri": "imap://billing"` and whose name does **not** exist yet in the
|
|
260
|
+
account.
|
|
261
|
+
- **Steps:**
|
|
262
|
+
```bash
|
|
263
|
+
cinna agent import MyAgents/Local/<agent> --yes
|
|
264
|
+
cinna account credentials list
|
|
265
|
+
```
|
|
266
|
+
- **Expected:** the draft is listed with `imap://billing` in the **Slot** column; after it is filled
|
|
267
|
+
in the browser, `cinna skills list <agent>` (if a skill declares the slot)
|
|
268
|
+
shows it ready. Re-running with `--update` does not change the URI of the
|
|
269
|
+
existing credential.
|
|
270
|
+
- **Watch for:** a draft created without the slot, so the reader falls back to
|
|
271
|
+
name matching; a second draft created because the slot differs.
|
|
272
|
+
|
|
273
|
+
### 10h. The engine travels at creation, and nothing else from `runtime` (contract 1.5.0)
|
|
274
|
+
|
|
275
|
+
- **Setup:** a fresh agent whose manifest carries
|
|
276
|
+
`"runtime": {"engine": "claude", "model": "claude-sonnet", "complexity": "medium"}`
|
|
277
|
+
and a handover with `"target_kind": "coordinator"`. Requires a cinna-core that
|
|
278
|
+
accepts `engine` on `POST /api/v1/cli/account/agents`.
|
|
279
|
+
- **Steps:**
|
|
280
|
+
```bash
|
|
281
|
+
cinna agent import MyAgents/Local/<agent> --dry-run
|
|
282
|
+
cinna agent import MyAgents/Local/<agent> --yes
|
|
283
|
+
cinna agent import MyAgents/Local/<agent> --update --yes
|
|
284
|
+
```
|
|
285
|
+
- **Expected:** both the dry run and the import print
|
|
286
|
+
`Engine: claude — sent as a preference (the cloud runs engines it does not support on OpenCode)`
|
|
287
|
+
and `Not carried to the cloud: runtime.model, runtime.complexity, handovers`;
|
|
288
|
+
the new agent's environment runs on Claude Code. Set `"engine": "codex"` on a
|
|
289
|
+
fresh agent: it imports and runs on OpenCode. The `--update` run prints
|
|
290
|
+
`Engine: claude — not applied: --update never changes an existing agent's engine`
|
|
291
|
+
and the environment is unchanged.
|
|
292
|
+
- **Watch for:** the import refusing an unknown engine; the model override
|
|
293
|
+
changing; an older cinna-core rejecting the create (it should ignore `engine`).
|
|
294
|
+
|
|
253
295
|
### 11. Verification loop the guide promises
|
|
254
296
|
|
|
255
297
|
- **Steps:**
|
{cinna_cli-0.4.3 → cinna_cli-0.5.1}/docs/features/local_agent_import/local_agent_import_tech.md
RENAMED
|
@@ -39,7 +39,7 @@ endpoint exists for this feature.
|
|
|
39
39
|
|
|
40
40
|
| Step | Call |
|
|
41
41
|
|------|------|
|
|
42
|
-
| 2 | `list_account_agents()` (resolve) / `create_agent(name, description, user_workspace_id=…)` |
|
|
42
|
+
| 2 | `list_account_agents()` (resolve) / `create_agent(name, description, user_workspace_id=…, engine=…)` — `engine` is in the body only when set |
|
|
43
43
|
| 3 | `update_agent_config(agent_id, fields)` → `PUT agents/{id}` **through the api-proxy escape hatch**, then `set_status_refresh_command(agent_id, cmd)` |
|
|
44
44
|
| 4 | `account.py:run_agent_sync(agent_id, None)` (mints the child token, provisions the workspace) — skipped when `resolve_child_workspace()` already finds one |
|
|
45
45
|
| 6 | `sync_session.ensure_session()` + `sync_session.flush()` — the same pair `cinna sync push` uses |
|
|
@@ -70,10 +70,59 @@ pragmatic subset `kit.py validate` checks:
|
|
|
70
70
|
- `slug` matches `^[a-z0-9][a-z0-9-]{1,62}$` **and** equals the folder name.
|
|
71
71
|
- `name` present, ≤ 255 chars; `description` a string when present.
|
|
72
72
|
- `prompts` an object; `example_prompts` a list of strings.
|
|
73
|
-
- Each credential has a non-empty `name` and `type
|
|
73
|
+
- Each credential has a non-empty `name` and `type`, and a `service_uri`
|
|
74
|
+
(contract 1.4.0, optional) is a non-empty string when present. Checked here
|
|
75
|
+
rather than left to the platform because the agent already exists by the time
|
|
76
|
+
`_sync_credentials()` sends it — a 422 there is a half-applied import.
|
|
74
77
|
- Each schedule has a name, a 5-field `cron_string`, a known `schedule_type`, and
|
|
75
78
|
a `command` when it is a script schedule.
|
|
76
79
|
|
|
80
|
+
`runtime` is **not** validated here — `read_runtime(manifest)` reads it
|
|
81
|
+
tolerantly after the manifest loads, because its fields are additive minors
|
|
82
|
+
that must never cost the import:
|
|
83
|
+
|
|
84
|
+
- `runtime` not an object, or `runtime.engine` not a string → a
|
|
85
|
+
`console.warn` naming the type, and no engine is sent.
|
|
86
|
+
- `runtime.engine` stripped; empty means absent. Otherwise sent raw — it is not
|
|
87
|
+
an enum, and the backend owns the mapping (`claude` → Claude Code, everything
|
|
88
|
+
it does not support → OpenCode, decision 4 of the 1.5.0 unification plan).
|
|
89
|
+
- The fields the cloud import does not carry are returned as dotted paths, in
|
|
90
|
+
a fixed order: `runtime.model`, `runtime.complexity`, `runtime.credential`,
|
|
91
|
+
`runtime.permissions` (`_UNCARRIED_RUNTIME_KEYS`), then any unknown
|
|
92
|
+
`runtime.*` key sorted, then `handovers` — the whole list, when it is
|
|
93
|
+
non-empty, because this import sends no handover at all; naming only
|
|
94
|
+
`handovers[].target_kind` would imply the rest of a handover travels — then
|
|
95
|
+
`capabilities`, when any of its keys has a value (`x-import: ignored`). A
|
|
96
|
+
key whose value is `null` counts as absent.
|
|
97
|
+
|
|
98
|
+
The engine reaches `_resolve_or_create_agent()` and is passed to
|
|
99
|
+
`create_agent()` **only on the create branch**. An agent resolved by id or
|
|
100
|
+
reattached by name keeps its engine: the id case says so in the step-1 `Engine:`
|
|
101
|
+
line (`known_agent_id` is known before the plan prints). `--update` without a
|
|
102
|
+
known id only learns at step 2 whether a name match exists, so its step-1 line
|
|
103
|
+
is the undecided one, and step 2 prints either the kept line (name-matched
|
|
104
|
+
resume) or the sent line (no match, agent created). The `Engine:` values,
|
|
105
|
+
verbatim:
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
Engine: claude — sent as a preference (the cloud runs engines it does not support on OpenCode)
|
|
109
|
+
Engine: claude — not applied: --update never changes an existing agent's engine
|
|
110
|
+
Engine: claude — sent only if this import creates the agent; --update keeps the engine of an existing agent it finds by name
|
|
111
|
+
Engine: not set — the cloud agent gets the platform's default
|
|
112
|
+
Not carried to the cloud: runtime.model, runtime.complexity, handovers
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The last line is printed only when the list is non-empty. The warnings:
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
! cinna-agent.json: 'runtime' is not an object (str) — ignored; the cloud agent gets the platform's default engine.
|
|
119
|
+
! cinna-agent.json: 'runtime.engine' is not a string (int) — ignored; the cloud agent gets the platform's default engine.
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Sending `engine` to an older cinna-core is safe: `AccountAgentCreateBody` is a
|
|
123
|
+
plain `SQLModel` with no `extra` setting, so pydantic's default (`ignore`)
|
|
124
|
+
drops the unknown field and the agent is created with the default engine.
|
|
125
|
+
|
|
77
126
|
Unknown keys are preserved: the dict is mutated and re-dumped, so a manifest
|
|
78
127
|
written by a newer kit survives a round-trip through an older CLI.
|
|
79
128
|
|
|
@@ -91,7 +140,39 @@ hosts read it — Cinna Desktop, cinna-core's `kit.py`, and this CLI — so the
|
|
|
91
140
|
folder rules are data rather than prose each host re-derives.
|
|
92
141
|
`src/cinna/kit_contract.py` is cinna-cli's reader and the port of the algorithms
|
|
93
142
|
that must stay byte-identical across hosts. `SUPPORTED_CONTRACT_VERSION` names
|
|
94
|
-
the contract version this build implements.
|
|
143
|
+
the contract version this build implements — **1.5.0**. It is the tool half of
|
|
144
|
+
the compatibility pair when no kit sits beside the agent, and it is the version
|
|
145
|
+
named in the `DEGRADED —` `Exclusions:` line.
|
|
146
|
+
|
|
147
|
+
### Contract 1.5.0 — what changed for this reader
|
|
148
|
+
|
|
149
|
+
1.5.0 brings the desktop's `runtime.engine`, `runtime.complexity` and
|
|
150
|
+
`handovers[].target_kind` into cinna-core's one manifest schema. Nothing this
|
|
151
|
+
module evaluates changed — `cloud_import_excludes`, `secret_files` and the
|
|
152
|
+
ledger schema are as in 1.4.0. The manifest side is `local_import.py`:
|
|
153
|
+
`runtime.engine` now reaches the platform at creation, and the fields the cloud
|
|
154
|
+
does not carry are printed (see *Manifest handling*).
|
|
155
|
+
|
|
156
|
+
### Contract 1.4.0 — what changed for this reader
|
|
157
|
+
|
|
158
|
+
1.4.0 (cloud and local credential delivery) is additive for cinna-cli; the
|
|
159
|
+
cross-repo checks below pass unchanged against cinna-core's 1.4.0 files.
|
|
160
|
+
|
|
161
|
+
- `cloud_import_excludes` is unchanged in content: `credentials/` was already
|
|
162
|
+
excluded whole, and the notes now say why (the platform regenerates
|
|
163
|
+
`credentials/README.md` and feeds it to the cloud prompt). `DEFAULT_EXCLUDE`
|
|
164
|
+
and `DEFAULT_SECRET_FILE_RULES` equal the 1.4.0 lists.
|
|
165
|
+
- `desktop_owned` shrank to a bare path list (the `contract_keys` block is
|
|
166
|
+
gone). This module does not read `desktop_owned`, so nothing depends on it.
|
|
167
|
+
- The manifest schema gained an optional `credentials[].service_uri`;
|
|
168
|
+
`local_import.py:load_manifest()` validates it and
|
|
169
|
+
`local_import.py:_sync_credentials()` passes it to
|
|
170
|
+
`client.py:AccountClient.create_credential()`.
|
|
171
|
+
- Credential values for a locally running agent come from cinna-core's
|
|
172
|
+
`/api/v1/external/credentials` routes (list, and a desktop-only
|
|
173
|
+
`materialize`), gated per credential by `allow_local_use`. Those are
|
|
174
|
+
desktop-JWT routes; `POST|PUT /api/v1/cli/account/credentials` do not accept
|
|
175
|
+
`allow_local_use` yet, so the CLI neither sends nor shows it.
|
|
95
176
|
|
|
96
177
|
### Finding it
|
|
97
178
|
|
|
@@ -293,7 +374,9 @@ failure warns and yields no file rather than aborting the import.
|
|
|
293
374
|
absent + no `--update` → create.
|
|
294
375
|
- **Credentials** — `list_credentials()` keyed by name; an existing name is only
|
|
295
376
|
*attached* (`share_credential_with_agent`), never recreated, so re-runs cannot
|
|
296
|
-
produce a second empty draft that shadows the filled one.
|
|
377
|
+
produce a second empty draft that shadows the filled one. Its `service_uri`
|
|
378
|
+
is not compared or rewritten either — the manifest's slot applies to a new
|
|
379
|
+
draft only.
|
|
297
380
|
- **Schedules** — `list_schedules()` keyed by name; existing + `--update` →
|
|
298
381
|
`update_schedule`, existing without `--update` → left alone with a notice.
|
|
299
382
|
- **Manifest settle** — `write_manifest()` runs after the confirmation and
|
|
@@ -316,7 +399,8 @@ failure warns and yields no file rather than aborting the import.
|
|
|
316
399
|
|
|
317
400
|
`--dry-run` returns before the first `AccountClient` is constructed and before
|
|
318
401
|
any local write: it prints the resolved plan (file list, credential drafts,
|
|
319
|
-
schedules,
|
|
402
|
+
schedules, the `Engine:` and `Not carried to the cloud:` lines,
|
|
403
|
+
create-vs-update) and stops. The test asserts the patched
|
|
320
404
|
`AccountClient` class was never called at all.
|
|
321
405
|
|
|
322
406
|
## Tests
|
|
@@ -386,4 +470,17 @@ against `publications.schema.json`.
|
|
|
386
470
|
- `run_agent_sync` is called exactly once when no workspace exists yet;
|
|
387
471
|
- `--no-push` and push-with-conflicts both leave the ledger unwritten;
|
|
388
472
|
- `layout.json` supplying the exclude list while `credentials/` stays excluded;
|
|
389
|
-
-
|
|
473
|
+
- a bad credential `service_uri` refused by `load_manifest()`, and a good one
|
|
474
|
+
reaching `create_credential()`;
|
|
475
|
+
- `--workspace` / `--name` threading and verbatim `PlatformError` surfacing;
|
|
476
|
+
- contract 1.5.0 runtime: `read_runtime()` over absent, null, blank, unknown and
|
|
477
|
+
full `runtime` blocks and empty/non-empty `handovers`; the stripped engine
|
|
478
|
+
reaching `create_agent()`; the default-engine line; a non-object `runtime`
|
|
479
|
+
and a non-string engine warning without refusing; the exact
|
|
480
|
+
`Not carried to the cloud:` line on a real run and on `--dry-run`, with no
|
|
481
|
+
runtime field in the metadata write; `--update` by id and by name match
|
|
482
|
+
leaving the engine alone and saying so once, and saying nothing when the
|
|
483
|
+
manifest names no engine.
|
|
484
|
+
|
|
485
|
+
`tests/test_client.py` asserts `create_agent()` puts `engine` in the body only
|
|
486
|
+
when it is set.
|
|
@@ -318,6 +318,7 @@ class AccountClient:
|
|
|
318
318
|
name: str,
|
|
319
319
|
description: str | None = None,
|
|
320
320
|
user_workspace_id: str | None = None,
|
|
321
|
+
engine: str | None = None,
|
|
321
322
|
) -> dict:
|
|
322
323
|
"""POST /api/v1/cli/account/agents — create an agent (thin client).
|
|
323
324
|
|
|
@@ -325,12 +326,20 @@ class AccountClient:
|
|
|
325
326
|
(AI credentials, env template, environment creation) and returns the
|
|
326
327
|
full agent record. ``user_workspace_id`` targets the account's active
|
|
327
328
|
user workspace (``None`` = Default).
|
|
329
|
+
|
|
330
|
+
``engine`` is a Local Agent Kit ``runtime.engine`` preference
|
|
331
|
+
(``opencode``, ``claude``, ``codex``, …), sent raw: the backend maps it
|
|
332
|
+
to the environment's SDK and runs an engine it does not support on
|
|
333
|
+
OpenCode. It is sent only when set — an older backend ignores the
|
|
334
|
+
unknown field, so sending it is backward compatible.
|
|
328
335
|
"""
|
|
329
336
|
body: dict = {"name": name}
|
|
330
337
|
if description is not None:
|
|
331
338
|
body["description"] = description
|
|
332
339
|
if user_workspace_id is not None:
|
|
333
340
|
body["user_workspace_id"] = user_workspace_id
|
|
341
|
+
if engine is not None:
|
|
342
|
+
body["engine"] = engine
|
|
334
343
|
response = self._client.post("/api/v1/cli/account/agents", json=body)
|
|
335
344
|
return self._handle_response(response).json()
|
|
336
345
|
|
|
@@ -78,8 +78,13 @@ def _emit_json(result) -> bool:
|
|
|
78
78
|
|
|
79
79
|
|
|
80
80
|
def _parse_artifacts(values: tuple[str, ...]) -> list[dict]:
|
|
81
|
-
"""Each ``--artifact`` must be a JSON object with kind
|
|
82
|
-
|
|
81
|
+
"""Each ``--artifact`` must be a JSON object with ``kind`` and ``name``.
|
|
82
|
+
|
|
83
|
+
A ``link`` needs an HTTP(S) ``ref`` — the only kind of reference another
|
|
84
|
+
agent can open. A ``file`` may leave ``ref`` out (the Cinna Task Protocol's
|
|
85
|
+
name-only file artifact, kit contract 1.6.0); when it carries one it must be
|
|
86
|
+
HTTP(S) too, never a local path.
|
|
87
|
+
"""
|
|
83
88
|
artifacts = []
|
|
84
89
|
for value in values:
|
|
85
90
|
try:
|
|
@@ -90,9 +95,10 @@ def _parse_artifacts(values: tuple[str, ...]) -> list[dict]:
|
|
|
90
95
|
raise click.BadParameter(
|
|
91
96
|
f"Not a JSON object: {value}", param_hint="--artifact"
|
|
92
97
|
)
|
|
98
|
+
required = ("kind", "name") if artifact.get("kind") == "file" and "ref" not in artifact else ("kind", "name", "ref")
|
|
93
99
|
missing = [
|
|
94
100
|
key
|
|
95
|
-
for key in
|
|
101
|
+
for key in required
|
|
96
102
|
if not isinstance(artifact.get(key), str) or not artifact[key].strip()
|
|
97
103
|
]
|
|
98
104
|
if missing:
|
|
@@ -100,7 +106,7 @@ def _parse_artifacts(values: tuple[str, ...]) -> list[dict]:
|
|
|
100
106
|
f"Artifact needs non-empty string {', '.join(missing)}: {value}",
|
|
101
107
|
param_hint="--artifact",
|
|
102
108
|
)
|
|
103
|
-
if urlparse(artifact["ref"]).scheme.lower() not in ("http", "https"):
|
|
109
|
+
if "ref" in artifact and urlparse(artifact["ref"]).scheme.lower() not in ("http", "https"):
|
|
104
110
|
raise click.BadParameter(
|
|
105
111
|
"Artifact ref must be an http(s) URL (upload local files first): "
|
|
106
112
|
f"{artifact['ref']}",
|
|
@@ -311,7 +317,7 @@ def status(task_id):
|
|
|
311
317
|
@click.option(
|
|
312
318
|
"--artifact",
|
|
313
319
|
multiple=True,
|
|
314
|
-
help='JSON object {"kind", "name", "ref"} with an http(s) ref; repeatable.',
|
|
320
|
+
help='JSON object {"kind", "name", "ref"} with an http(s) ref; a "file" may omit ref; repeatable.',
|
|
315
321
|
)
|
|
316
322
|
@click.option("--body", default="", help="The full result text.")
|
|
317
323
|
def report(task_id, result_status, summary, question, audience, artifact, body):
|
|
@@ -24,7 +24,12 @@ rather than compute it a different way. The safe direction is a property of the
|
|
|
24
24
|
consequence, not a house style.
|
|
25
25
|
|
|
26
26
|
Ported from cinna-core's ``docs/local_agent_kit/tools/kit.py``, which is the
|
|
27
|
-
reference implementation, at contract version 1.0.0
|
|
27
|
+
reference implementation, at contract version 1.0.0; the offline fallbacks below
|
|
28
|
+
are checked against contract 1.5.0. Neither 1.4.0 (cloud and local credential
|
|
29
|
+
delivery — ``credentials/`` was already excluded whole) nor 1.5.0 (the
|
|
30
|
+
``runtime.engine``/``runtime.complexity``/``handovers[].target_kind`` manifest
|
|
31
|
+
fields brought into core's schema, read by :mod:`cinna.local_import`) changed
|
|
32
|
+
anything this module evaluates.
|
|
28
33
|
"""
|
|
29
34
|
|
|
30
35
|
from __future__ import annotations
|
|
@@ -54,7 +59,7 @@ CONTRACT_VERSION_FILENAME = "CONTRACT_VERSION"
|
|
|
54
59
|
|
|
55
60
|
#: The contract version this CLI implements. Only the MAJOR component is a
|
|
56
61
|
#: compatibility question — see ``check_contract_compatibility``.
|
|
57
|
-
SUPPORTED_CONTRACT_VERSION = "1.
|
|
62
|
+
SUPPORTED_CONTRACT_VERSION = "1.6.0"
|
|
58
63
|
|
|
59
64
|
|
|
60
65
|
# ── Offline fallbacks ───────────────────────────────────────────────────────
|