healthcloud-cli 3.7.2__tar.gz → 3.7.5__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.
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/PKG-INFO +73 -28
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/README.md +72 -27
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/agents/commands.py +79 -10
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/agents/operations.py +149 -24
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/auth.py +25 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/departments/commands.py +58 -11
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/departments/operations.py +108 -1
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/errors.py +46 -23
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/policies/commands.py +2 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/skills/commands.py +2 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/teams/commands.py +4 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/pyproject.toml +1 -1
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/.gitignore +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/hatch_build.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/__init__.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/admins/__init__.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/admins/commands.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/admins/group.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/admins/operations.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/__init__.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/agents/__init__.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/agents/group.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/agents/projections.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/commands.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/compatibility.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/context.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/data_sources/__init__.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/data_sources/commands.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/data_sources/group.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/data_sources/operations.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/data_sources/projections.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/departments/__init__.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/departments/group.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/departments/projections.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/domain_errors.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/group.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/guardrails/__init__.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/guardrails/commands.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/guardrails/group.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/guardrails/operations.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/guardrails/projections.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/organization/__init__.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/organization/commands.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/organization/group.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/organization/operations.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/organization/projections.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/output.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/policies/__init__.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/policies/group.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/policies/operations.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/policies/projections.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/pretty.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/registry.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/results.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/session.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/sessions/__init__.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/sessions/commands.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/sessions/group.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/sessions/operations.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/sessions/projections.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/skills/__init__.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/skills/group.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/skills/operations.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/skills/projections.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/target.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/teams/__init__.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/teams/group.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/teams/operations.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/teams/projections.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/tools/__init__.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/tools/commands.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/tools/group.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/tools/operations.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/tools/projections.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/tuning.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/ui.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/ams/windows_files.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/cli.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/context.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/contracts/__init__.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/contracts/mcp-tools.manifest.json +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/main.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/manifest.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/output.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/params.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/tenants/__init__.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/tenants/commands.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/tenants/group.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/tenants/operations.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/healthcloud_cli/util.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/scripts/__init__.py +0 -0
- {healthcloud_cli-3.7.2 → healthcloud_cli-3.7.5}/scripts/bundle_manifest.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: healthcloud-cli
|
|
3
|
-
Version: 3.7.
|
|
3
|
+
Version: 3.7.5
|
|
4
4
|
Summary: Command-line interface for the HealthCloud MCP gateway, generated from the shared MCP tool manifest.
|
|
5
5
|
Project-URL: Issues, https://github.com/healthcloudservices/healthcloud-services/issues
|
|
6
6
|
Project-URL: Repository, https://github.com/healthcloudservices/healthcloud-services
|
|
@@ -576,11 +576,23 @@ raw JSON line. `--output json` prints the full envelope above, byte-identical to
|
|
|
576
576
|
before. An unknown outcome still prints its one-line `error:` plus the
|
|
577
577
|
reconciliation on stderr.
|
|
578
578
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
579
|
+
Without `--confirm` the command is a **preview**: it re-reads the agent exactly
|
|
580
|
+
once (the same one bounded `GET`), runs the same local pre-checks, prints
|
|
581
|
+
`preview: --confirm was not passed, so nothing has been sent.` and then the
|
|
582
|
+
resolved change to stderr — the target (`agent_id`, `name`, `type`,
|
|
583
|
+
`config_version`), `status` and `active` before -> after, and
|
|
584
|
+
`one PUT /agents/{agent_id} with body keys: status, active` — and exits 2 having
|
|
585
|
+
sent nothing. With `--confirm` the write path is unchanged: it re-reads before
|
|
586
|
+
the single `PUT`, so a preview is never an approval token. The preview text is
|
|
587
|
+
suppressed under `--output json`/`raw` (the same rule the confirmed path's
|
|
588
|
+
review follows) so those modes keep stderr machine-parsable.
|
|
589
|
+
|
|
590
|
+
Pre-checks refuse with exit 1 and **no write**: an agent outside the explicit
|
|
591
|
+
tenant, an already in-effect state, an unsupported `archived`/`draft` target
|
|
592
|
+
(named as having no supported reversible transition here), or a
|
|
593
|
+
`config_version` that no longer matches `--expected-config-version` — all of
|
|
594
|
+
these are also enforced by the preview, which still sends nothing. A missing
|
|
595
|
+
`--confirm` exits 2. That version check is a local best-effort
|
|
584
596
|
guard only: the route has no `If-Match` and the server never compares the
|
|
585
597
|
version, so it cannot prove atomicity and a request could still race between
|
|
586
598
|
the read and the PUT.
|
|
@@ -657,15 +669,23 @@ the server checks tenant scope only for the department, team, skill, policy and
|
|
|
657
669
|
guardrail references. This command does not imply otherwise, and it does not
|
|
658
670
|
re-implement the server's reference checks.
|
|
659
671
|
|
|
660
|
-
|
|
661
|
-
|
|
672
|
+
Without `--confirm` the command is a **preview**: it reads the agent exactly once
|
|
673
|
+
(the same one bounded `GET`), computes the same reviewed diff and runs the same
|
|
674
|
+
local pre-checks, prints `preview: --confirm was not passed, so nothing has been
|
|
675
|
+
sent.` followed by the reviewed diff, and exits 2 having sent no `PUT`. With
|
|
676
|
+
`--confirm` the write path is unchanged: it re-reads before the single `PUT`, so
|
|
677
|
+
a preview is never an approval token. The preview text is suppressed under
|
|
678
|
+
`--output json`/`raw`, like the confirmed path's review.
|
|
679
|
+
|
|
680
|
+
Pre-checks refuse with exit 1 and **no write**: no assignment option at all
|
|
662
681
|
(exit 2), setting and clearing the same family together (exit 2), an agent
|
|
663
682
|
outside the explicit tenant, a request where every reference already equals the
|
|
664
683
|
read state ("already in effect"), or a `config_version` that no longer matches
|
|
665
|
-
`--expected-config-version
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
the
|
|
684
|
+
`--expected-config-version` — all of these are also enforced by the preview,
|
|
685
|
+
which still sends nothing. A missing `--confirm` exits 2. That version check is
|
|
686
|
+
a local best-effort guard only: the route has no `If-Match` and the server never
|
|
687
|
+
compares the version, so it cannot prove atomicity and a request could still
|
|
688
|
+
race between the read and the PUT. Operation-specific approval here is the CLI's own `--confirm` plus the
|
|
669
689
|
reviewed diff, deliberately separate from the tuning/plan-apply approval path;
|
|
670
690
|
the server enforces tenant isolation, reference existence and the audit log, and
|
|
671
691
|
it has **no** assignment approval or consent entity.
|
|
@@ -733,10 +753,17 @@ disclosure: `agent_id`, `deleted: true`, `target`, `disclosure`, `evidence`
|
|
|
733
753
|
reviewed target and disclosure above are still printed to stderr in `pretty`
|
|
734
754
|
mode only; `--output json`/`raw` keep stderr machine-parsable.
|
|
735
755
|
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
756
|
+
Without `--confirm` the command is a **preview**: it reads the agent exactly once
|
|
757
|
+
(the same one bounded `GET`), prints `preview: --confirm was not passed, so
|
|
758
|
+
nothing has been sent.` plus the resolved destructive target and the whole
|
|
759
|
+
disclosure block to stderr, and exits 2 having sent no `DELETE`. With `--confirm`
|
|
760
|
+
the sequence above is unchanged: it re-reads before the single `DELETE`, so a
|
|
761
|
+
preview is never an approval token. The preview text is suppressed under
|
|
762
|
+
`--output json`/`raw`, like the confirmed path's review.
|
|
763
|
+
|
|
764
|
+
Refusals claim nothing and send nothing extra: an agent outside the explicit
|
|
765
|
+
tenant, the tenant identity mismatch and a delete target that no longer exists
|
|
766
|
+
are refused before the `DELETE` (the preview reports the same `not_found`); a `409` is a `conflict` refusal naming the referring
|
|
740
767
|
schedules; a `404` from the `DELETE` is `not_found`; and a `405` is the server's
|
|
741
768
|
refusal (`unsupported`). None of them is retried.
|
|
742
769
|
|
|
@@ -770,25 +797,39 @@ and the result envelope carries the server's authoritative readback of the
|
|
|
770
797
|
department (same bounded projection as reads):
|
|
771
798
|
|
|
772
799
|
```bash
|
|
773
|
-
uv run --frozen hc ams departments create --environment dev --tenant-id TENANT_ID --name "Clinical Operations"
|
|
800
|
+
uv run --frozen hc ams departments create --environment dev --tenant-id TENANT_ID --name "Clinical Operations" [--description TEXT] [--parent-department-id PARENT_ID] [--key KEY] [--required-eval-suite-ids SUITE_ID ...]
|
|
774
801
|
uv run --frozen hc ams departments update --environment dev --tenant-id TENANT_ID --department-id DEPARTMENT_ID [--name NAME] [--description TEXT] [--parent-department-id PARENT_ID] [--key KEY] [--required-eval-suite-ids SUITE_ID ...]
|
|
775
802
|
uv run --frozen hc ams departments set-active --environment dev --tenant-id TENANT_ID --department-id DEPARTMENT_ID
|
|
776
803
|
uv run --frozen hc ams departments deactivate --environment dev --tenant-id TENANT_ID --department-id DEPARTMENT_ID
|
|
777
|
-
uv run --frozen hc ams departments delete --environment dev --tenant-id TENANT_ID --department-id DEPARTMENT_ID
|
|
804
|
+
uv run --frozen hc ams departments delete --environment dev --tenant-id TENANT_ID --department-id DEPARTMENT_ID [--confirm]
|
|
778
805
|
```
|
|
779
806
|
|
|
780
807
|
- `create` succeeds with `operation: "departments.create"` and
|
|
781
|
-
`data.department` = the server's 201 readback. `--name`
|
|
782
|
-
|
|
783
|
-
|
|
808
|
+
`data.department` = the server's 201 readback. `--name` is required. There is
|
|
809
|
+
no creator flag: before the write the CLI reads the saved session's own
|
|
810
|
+
identity (`GET /admins/me`) and sends it as the server contract's
|
|
811
|
+
`created_by_user_id`, so a create can never be attributed to another admin
|
|
812
|
+
and the tenant is taken from that same authenticated admin. A failed identity
|
|
813
|
+
read is a bounded failure and the write is never sent — it is not reported as
|
|
814
|
+
an unknown outcome.
|
|
784
815
|
- `update` sends only the options you pass (an empty `--description ""`
|
|
785
816
|
clears it); it refuses with exit 1 (`validation`) when no field option is
|
|
786
817
|
given. `set-active` and `deactivate` mark the department active/inactive.
|
|
787
|
-
- `delete` succeeds with `data: {"deleted": true}` (the server
|
|
788
|
-
with no body) and is irreversible.
|
|
818
|
+
- `delete --confirm` succeeds with `data: {"deleted": true}` (the server
|
|
819
|
+
answers 204 with no body) and is irreversible: the CLI keeps no restore.
|
|
820
|
+
Without `--confirm` the command is a **preview**: it reads the department
|
|
821
|
+
exactly once (one bounded `GET`), prints `preview: --confirm was not passed,
|
|
822
|
+
so nothing has been sent.` plus the resolved target and the disclosure block
|
|
823
|
+
to stderr, and exits 2 having sent no `DELETE`. With `--confirm` the confirmed
|
|
824
|
+
run makes the same single `GET` before its single `DELETE`, and the result
|
|
825
|
+
envelope is the same, so a preview is never an approval token. The preview
|
|
826
|
+
text is suppressed under `--output json`/`raw`, which keep stderr
|
|
827
|
+
machine-parsable (the exit-2 refusal message itself is plain text on stderr;
|
|
828
|
+
see #890).
|
|
789
829
|
- A 404 for the requested department is a `not_found` refusal naming the ID
|
|
790
830
|
(on `create`, a 404 names the referenced department — typically the missing
|
|
791
|
-
`--parent-department-id
|
|
831
|
+
`--parent-department-id`; on `delete`, the reviewed read refuses identically
|
|
832
|
+
and nothing is sent); a target/tenant or identity mismatch is a
|
|
792
833
|
`validation` refusal; both exit 1
|
|
793
834
|
without changes. The one exception is a tenant mismatch on the `create`
|
|
794
835
|
readback: the department has already been created server-side, so the CLI
|
|
@@ -822,7 +863,7 @@ projection as reads). Teams have no active/inactive lifecycle, so there are no
|
|
|
822
863
|
|
|
823
864
|
```bash
|
|
824
865
|
uv run --frozen hc ams teams create --environment dev --tenant-id TENANT_ID --name "Escalation Team" --department-id DEPARTMENT_ID --created-by-user-id ADMIN_USER_ID [--description TEXT] [--key KEY] [--required-eval-suite-ids SUITE_ID ...]
|
|
825
|
-
uv run --frozen hc ams teams update --environment dev --tenant-id TENANT_ID --team-id TEAM_ID [--name NAME] [--description TEXT] [--key KEY] [--required-eval-suite-ids SUITE_ID ...]
|
|
866
|
+
uv run --frozen hc ams teams update --environment dev --tenant-id TENANT_ID --team-id TEAM_ID [--name NAME] [--description TEXT] [--key KEY] [--required-eval-suite-ids SUITE_ID ... | --clear-required-eval-suite-ids]
|
|
826
867
|
uv run --frozen hc ams teams delete --environment dev --tenant-id TENANT_ID --team-id TEAM_ID
|
|
827
868
|
```
|
|
828
869
|
|
|
@@ -834,7 +875,8 @@ uv run --frozen hc ams teams delete --environment dev --tenant-id TENANT_ID --
|
|
|
834
875
|
clears it; `--clear-required-eval-suite-ids` sends an empty list to clear
|
|
835
876
|
the required evaluation suites; `--key` accepts a nonblank key, it cannot be
|
|
836
877
|
blanked); it refuses with exit 1 (`validation`) when no field option is
|
|
837
|
-
given.
|
|
878
|
+
given. `--required-eval-suite-ids` and `--clear-required-eval-suite-ids` are
|
|
879
|
+
alternatives: passing both is a usage error (exit 2) and nothing is sent.
|
|
838
880
|
- `delete` succeeds with `data: {"deleted": true}` (the server answers 204
|
|
839
881
|
with no body) and is irreversible. When AI agents still reference the team,
|
|
840
882
|
the server refuses with 409 and the CLI reports one `conflict` refusal that
|
|
@@ -901,7 +943,8 @@ uv run --frozen hc ams skills delete --environment dev --tenant-id TENANT_ID --s
|
|
|
901
943
|
- `update` sends only the options you pass (an empty `--description ""`
|
|
902
944
|
clears it; `--clear-tool-ids` sends an explicit empty list to clear the
|
|
903
945
|
skill's tool bindings); it refuses with exit 1 (`validation`) when no field
|
|
904
|
-
option is given.
|
|
946
|
+
option is given. `--tool-ids` and `--clear-tool-ids` are alternatives:
|
|
947
|
+
passing both is a usage error (exit 2) and nothing is sent.
|
|
905
948
|
- `delete` succeeds with `data: {"deleted": true}` (the server answers 204
|
|
906
949
|
with no body) and is irreversible. When AI agents still reference the skill
|
|
907
950
|
(via their `skill_ids`), the server refuses with 409 and the CLI reports one
|
|
@@ -993,7 +1036,9 @@ uv run --frozen hc ams policies delete --environment dev --tenant-id TENANT_ID -
|
|
|
993
1036
|
- `update` sends only the options you pass (an empty `--description ""` or
|
|
994
1037
|
`--content ""` clears it; `--clear-guardrail-ids` sends an explicit empty
|
|
995
1038
|
list to clear the policy's guardrail bindings); it refuses with exit 1
|
|
996
|
-
(`validation`) when no field option is given.
|
|
1039
|
+
(`validation`) when no field option is given. `--guardrail-ids` and
|
|
1040
|
+
`--clear-guardrail-ids` are alternatives: passing both is a usage error
|
|
1041
|
+
(exit 2) and nothing is sent.
|
|
997
1042
|
- `activate`/`deactivate` PUT `active: true|false` and succeed only when the
|
|
998
1043
|
readback confirms the requested flag.
|
|
999
1044
|
- `delete` succeeds with `data: {"deleted": true}` (the server answers 204
|
|
@@ -558,11 +558,23 @@ raw JSON line. `--output json` prints the full envelope above, byte-identical to
|
|
|
558
558
|
before. An unknown outcome still prints its one-line `error:` plus the
|
|
559
559
|
reconciliation on stderr.
|
|
560
560
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
561
|
+
Without `--confirm` the command is a **preview**: it re-reads the agent exactly
|
|
562
|
+
once (the same one bounded `GET`), runs the same local pre-checks, prints
|
|
563
|
+
`preview: --confirm was not passed, so nothing has been sent.` and then the
|
|
564
|
+
resolved change to stderr — the target (`agent_id`, `name`, `type`,
|
|
565
|
+
`config_version`), `status` and `active` before -> after, and
|
|
566
|
+
`one PUT /agents/{agent_id} with body keys: status, active` — and exits 2 having
|
|
567
|
+
sent nothing. With `--confirm` the write path is unchanged: it re-reads before
|
|
568
|
+
the single `PUT`, so a preview is never an approval token. The preview text is
|
|
569
|
+
suppressed under `--output json`/`raw` (the same rule the confirmed path's
|
|
570
|
+
review follows) so those modes keep stderr machine-parsable.
|
|
571
|
+
|
|
572
|
+
Pre-checks refuse with exit 1 and **no write**: an agent outside the explicit
|
|
573
|
+
tenant, an already in-effect state, an unsupported `archived`/`draft` target
|
|
574
|
+
(named as having no supported reversible transition here), or a
|
|
575
|
+
`config_version` that no longer matches `--expected-config-version` — all of
|
|
576
|
+
these are also enforced by the preview, which still sends nothing. A missing
|
|
577
|
+
`--confirm` exits 2. That version check is a local best-effort
|
|
566
578
|
guard only: the route has no `If-Match` and the server never compares the
|
|
567
579
|
version, so it cannot prove atomicity and a request could still race between
|
|
568
580
|
the read and the PUT.
|
|
@@ -639,15 +651,23 @@ the server checks tenant scope only for the department, team, skill, policy and
|
|
|
639
651
|
guardrail references. This command does not imply otherwise, and it does not
|
|
640
652
|
re-implement the server's reference checks.
|
|
641
653
|
|
|
642
|
-
|
|
643
|
-
|
|
654
|
+
Without `--confirm` the command is a **preview**: it reads the agent exactly once
|
|
655
|
+
(the same one bounded `GET`), computes the same reviewed diff and runs the same
|
|
656
|
+
local pre-checks, prints `preview: --confirm was not passed, so nothing has been
|
|
657
|
+
sent.` followed by the reviewed diff, and exits 2 having sent no `PUT`. With
|
|
658
|
+
`--confirm` the write path is unchanged: it re-reads before the single `PUT`, so
|
|
659
|
+
a preview is never an approval token. The preview text is suppressed under
|
|
660
|
+
`--output json`/`raw`, like the confirmed path's review.
|
|
661
|
+
|
|
662
|
+
Pre-checks refuse with exit 1 and **no write**: no assignment option at all
|
|
644
663
|
(exit 2), setting and clearing the same family together (exit 2), an agent
|
|
645
664
|
outside the explicit tenant, a request where every reference already equals the
|
|
646
665
|
read state ("already in effect"), or a `config_version` that no longer matches
|
|
647
|
-
`--expected-config-version
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
the
|
|
666
|
+
`--expected-config-version` — all of these are also enforced by the preview,
|
|
667
|
+
which still sends nothing. A missing `--confirm` exits 2. That version check is
|
|
668
|
+
a local best-effort guard only: the route has no `If-Match` and the server never
|
|
669
|
+
compares the version, so it cannot prove atomicity and a request could still
|
|
670
|
+
race between the read and the PUT. Operation-specific approval here is the CLI's own `--confirm` plus the
|
|
651
671
|
reviewed diff, deliberately separate from the tuning/plan-apply approval path;
|
|
652
672
|
the server enforces tenant isolation, reference existence and the audit log, and
|
|
653
673
|
it has **no** assignment approval or consent entity.
|
|
@@ -715,10 +735,17 @@ disclosure: `agent_id`, `deleted: true`, `target`, `disclosure`, `evidence`
|
|
|
715
735
|
reviewed target and disclosure above are still printed to stderr in `pretty`
|
|
716
736
|
mode only; `--output json`/`raw` keep stderr machine-parsable.
|
|
717
737
|
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
738
|
+
Without `--confirm` the command is a **preview**: it reads the agent exactly once
|
|
739
|
+
(the same one bounded `GET`), prints `preview: --confirm was not passed, so
|
|
740
|
+
nothing has been sent.` plus the resolved destructive target and the whole
|
|
741
|
+
disclosure block to stderr, and exits 2 having sent no `DELETE`. With `--confirm`
|
|
742
|
+
the sequence above is unchanged: it re-reads before the single `DELETE`, so a
|
|
743
|
+
preview is never an approval token. The preview text is suppressed under
|
|
744
|
+
`--output json`/`raw`, like the confirmed path's review.
|
|
745
|
+
|
|
746
|
+
Refusals claim nothing and send nothing extra: an agent outside the explicit
|
|
747
|
+
tenant, the tenant identity mismatch and a delete target that no longer exists
|
|
748
|
+
are refused before the `DELETE` (the preview reports the same `not_found`); a `409` is a `conflict` refusal naming the referring
|
|
722
749
|
schedules; a `404` from the `DELETE` is `not_found`; and a `405` is the server's
|
|
723
750
|
refusal (`unsupported`). None of them is retried.
|
|
724
751
|
|
|
@@ -752,25 +779,39 @@ and the result envelope carries the server's authoritative readback of the
|
|
|
752
779
|
department (same bounded projection as reads):
|
|
753
780
|
|
|
754
781
|
```bash
|
|
755
|
-
uv run --frozen hc ams departments create --environment dev --tenant-id TENANT_ID --name "Clinical Operations"
|
|
782
|
+
uv run --frozen hc ams departments create --environment dev --tenant-id TENANT_ID --name "Clinical Operations" [--description TEXT] [--parent-department-id PARENT_ID] [--key KEY] [--required-eval-suite-ids SUITE_ID ...]
|
|
756
783
|
uv run --frozen hc ams departments update --environment dev --tenant-id TENANT_ID --department-id DEPARTMENT_ID [--name NAME] [--description TEXT] [--parent-department-id PARENT_ID] [--key KEY] [--required-eval-suite-ids SUITE_ID ...]
|
|
757
784
|
uv run --frozen hc ams departments set-active --environment dev --tenant-id TENANT_ID --department-id DEPARTMENT_ID
|
|
758
785
|
uv run --frozen hc ams departments deactivate --environment dev --tenant-id TENANT_ID --department-id DEPARTMENT_ID
|
|
759
|
-
uv run --frozen hc ams departments delete --environment dev --tenant-id TENANT_ID --department-id DEPARTMENT_ID
|
|
786
|
+
uv run --frozen hc ams departments delete --environment dev --tenant-id TENANT_ID --department-id DEPARTMENT_ID [--confirm]
|
|
760
787
|
```
|
|
761
788
|
|
|
762
789
|
- `create` succeeds with `operation: "departments.create"` and
|
|
763
|
-
`data.department` = the server's 201 readback. `--name`
|
|
764
|
-
|
|
765
|
-
|
|
790
|
+
`data.department` = the server's 201 readback. `--name` is required. There is
|
|
791
|
+
no creator flag: before the write the CLI reads the saved session's own
|
|
792
|
+
identity (`GET /admins/me`) and sends it as the server contract's
|
|
793
|
+
`created_by_user_id`, so a create can never be attributed to another admin
|
|
794
|
+
and the tenant is taken from that same authenticated admin. A failed identity
|
|
795
|
+
read is a bounded failure and the write is never sent — it is not reported as
|
|
796
|
+
an unknown outcome.
|
|
766
797
|
- `update` sends only the options you pass (an empty `--description ""`
|
|
767
798
|
clears it); it refuses with exit 1 (`validation`) when no field option is
|
|
768
799
|
given. `set-active` and `deactivate` mark the department active/inactive.
|
|
769
|
-
- `delete` succeeds with `data: {"deleted": true}` (the server
|
|
770
|
-
with no body) and is irreversible.
|
|
800
|
+
- `delete --confirm` succeeds with `data: {"deleted": true}` (the server
|
|
801
|
+
answers 204 with no body) and is irreversible: the CLI keeps no restore.
|
|
802
|
+
Without `--confirm` the command is a **preview**: it reads the department
|
|
803
|
+
exactly once (one bounded `GET`), prints `preview: --confirm was not passed,
|
|
804
|
+
so nothing has been sent.` plus the resolved target and the disclosure block
|
|
805
|
+
to stderr, and exits 2 having sent no `DELETE`. With `--confirm` the confirmed
|
|
806
|
+
run makes the same single `GET` before its single `DELETE`, and the result
|
|
807
|
+
envelope is the same, so a preview is never an approval token. The preview
|
|
808
|
+
text is suppressed under `--output json`/`raw`, which keep stderr
|
|
809
|
+
machine-parsable (the exit-2 refusal message itself is plain text on stderr;
|
|
810
|
+
see #890).
|
|
771
811
|
- A 404 for the requested department is a `not_found` refusal naming the ID
|
|
772
812
|
(on `create`, a 404 names the referenced department — typically the missing
|
|
773
|
-
`--parent-department-id
|
|
813
|
+
`--parent-department-id`; on `delete`, the reviewed read refuses identically
|
|
814
|
+
and nothing is sent); a target/tenant or identity mismatch is a
|
|
774
815
|
`validation` refusal; both exit 1
|
|
775
816
|
without changes. The one exception is a tenant mismatch on the `create`
|
|
776
817
|
readback: the department has already been created server-side, so the CLI
|
|
@@ -804,7 +845,7 @@ projection as reads). Teams have no active/inactive lifecycle, so there are no
|
|
|
804
845
|
|
|
805
846
|
```bash
|
|
806
847
|
uv run --frozen hc ams teams create --environment dev --tenant-id TENANT_ID --name "Escalation Team" --department-id DEPARTMENT_ID --created-by-user-id ADMIN_USER_ID [--description TEXT] [--key KEY] [--required-eval-suite-ids SUITE_ID ...]
|
|
807
|
-
uv run --frozen hc ams teams update --environment dev --tenant-id TENANT_ID --team-id TEAM_ID [--name NAME] [--description TEXT] [--key KEY] [--required-eval-suite-ids SUITE_ID ...]
|
|
848
|
+
uv run --frozen hc ams teams update --environment dev --tenant-id TENANT_ID --team-id TEAM_ID [--name NAME] [--description TEXT] [--key KEY] [--required-eval-suite-ids SUITE_ID ... | --clear-required-eval-suite-ids]
|
|
808
849
|
uv run --frozen hc ams teams delete --environment dev --tenant-id TENANT_ID --team-id TEAM_ID
|
|
809
850
|
```
|
|
810
851
|
|
|
@@ -816,7 +857,8 @@ uv run --frozen hc ams teams delete --environment dev --tenant-id TENANT_ID --
|
|
|
816
857
|
clears it; `--clear-required-eval-suite-ids` sends an empty list to clear
|
|
817
858
|
the required evaluation suites; `--key` accepts a nonblank key, it cannot be
|
|
818
859
|
blanked); it refuses with exit 1 (`validation`) when no field option is
|
|
819
|
-
given.
|
|
860
|
+
given. `--required-eval-suite-ids` and `--clear-required-eval-suite-ids` are
|
|
861
|
+
alternatives: passing both is a usage error (exit 2) and nothing is sent.
|
|
820
862
|
- `delete` succeeds with `data: {"deleted": true}` (the server answers 204
|
|
821
863
|
with no body) and is irreversible. When AI agents still reference the team,
|
|
822
864
|
the server refuses with 409 and the CLI reports one `conflict` refusal that
|
|
@@ -883,7 +925,8 @@ uv run --frozen hc ams skills delete --environment dev --tenant-id TENANT_ID --s
|
|
|
883
925
|
- `update` sends only the options you pass (an empty `--description ""`
|
|
884
926
|
clears it; `--clear-tool-ids` sends an explicit empty list to clear the
|
|
885
927
|
skill's tool bindings); it refuses with exit 1 (`validation`) when no field
|
|
886
|
-
option is given.
|
|
928
|
+
option is given. `--tool-ids` and `--clear-tool-ids` are alternatives:
|
|
929
|
+
passing both is a usage error (exit 2) and nothing is sent.
|
|
887
930
|
- `delete` succeeds with `data: {"deleted": true}` (the server answers 204
|
|
888
931
|
with no body) and is irreversible. When AI agents still reference the skill
|
|
889
932
|
(via their `skill_ids`), the server refuses with 409 and the CLI reports one
|
|
@@ -975,7 +1018,9 @@ uv run --frozen hc ams policies delete --environment dev --tenant-id TENANT_ID -
|
|
|
975
1018
|
- `update` sends only the options you pass (an empty `--description ""` or
|
|
976
1019
|
`--content ""` clears it; `--clear-guardrail-ids` sends an explicit empty
|
|
977
1020
|
list to clear the policy's guardrail bindings); it refuses with exit 1
|
|
978
|
-
(`validation`) when no field option is given.
|
|
1021
|
+
(`validation`) when no field option is given. `--guardrail-ids` and
|
|
1022
|
+
`--clear-guardrail-ids` are alternatives: passing both is a usage error
|
|
1023
|
+
(exit 2) and nothing is sent.
|
|
979
1024
|
- `activate`/`deactivate` PUT `active: true|false` and succeed only when the
|
|
980
1025
|
readback confirms the requested flag.
|
|
981
1026
|
- `delete` succeeds with `data: {"deleted": true}` (the server answers 204
|
|
@@ -7,7 +7,7 @@ from pathlib import Path
|
|
|
7
7
|
import click
|
|
8
8
|
|
|
9
9
|
from ..context import AmsDependencies, pass_ams, preflight_agents
|
|
10
|
-
from ..errors import run_domain
|
|
10
|
+
from ..errors import run_domain, run_preview
|
|
11
11
|
from ..session import resolve_tenant_target
|
|
12
12
|
from .operations import (
|
|
13
13
|
ASSIGNMENT_FAMILIES,
|
|
@@ -16,6 +16,9 @@ from .operations import (
|
|
|
16
16
|
export_agent,
|
|
17
17
|
get_agent,
|
|
18
18
|
list_agents,
|
|
19
|
+
preview_assignments,
|
|
20
|
+
preview_delete,
|
|
21
|
+
preview_lifecycle,
|
|
19
22
|
set_assignments,
|
|
20
23
|
set_lifecycle,
|
|
21
24
|
)
|
|
@@ -37,6 +40,34 @@ def _agent(function):
|
|
|
37
40
|
return click.option("--agent-id", required=True)(function)
|
|
38
41
|
|
|
39
42
|
|
|
43
|
+
def _preview_then_refuse(
|
|
44
|
+
invocation,
|
|
45
|
+
operation: str,
|
|
46
|
+
target_data: dict,
|
|
47
|
+
preview,
|
|
48
|
+
refusal: str,
|
|
49
|
+
*,
|
|
50
|
+
login_hint: str,
|
|
51
|
+
) -> None:
|
|
52
|
+
"""Read the target once, print the reviewed change, then refuse with exit 2.
|
|
53
|
+
|
|
54
|
+
Nothing is written before the refusal, and the preview is still a read: a
|
|
55
|
+
failed read (not logged in, wrong tenant, 404, transport) keeps the bounded
|
|
56
|
+
error envelope instead of escaping as a traceback. The confirmed run
|
|
57
|
+
re-reads before its single write, so a preview is never an approval token.
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
def read() -> None:
|
|
61
|
+
_require_login(login_hint)
|
|
62
|
+
target = resolve_tenant_target(target_data["environment"], target_data["tenant_id"])
|
|
63
|
+
target_data.update(environment=target.environment, tenant_id=target.tenant_id)
|
|
64
|
+
preflight_agents(invocation, target, methods=("get_agent",))
|
|
65
|
+
preview(target)
|
|
66
|
+
|
|
67
|
+
run_preview(operation, target_data, read)
|
|
68
|
+
raise click.UsageError(refusal)
|
|
69
|
+
|
|
70
|
+
|
|
40
71
|
def _require_login(hint: str = LOGIN_HINT) -> None:
|
|
41
72
|
"""Agent writes need a saved `hc login` session, not env-var credentials."""
|
|
42
73
|
|
|
@@ -71,7 +102,8 @@ def create_lifecycle_command(dependencies: AmsDependencies, transition: str) ->
|
|
|
71
102
|
"--confirm",
|
|
72
103
|
is_flag=True,
|
|
73
104
|
default=False,
|
|
74
|
-
help="Required acknowledgement of the exact target and state; without it
|
|
105
|
+
help="Required acknowledgement of the exact target and state; without it the command reads the "
|
|
106
|
+
"target, prints the change and sends nothing.",
|
|
75
107
|
)
|
|
76
108
|
@pass_ams
|
|
77
109
|
def command(
|
|
@@ -82,14 +114,27 @@ def create_lifecycle_command(dependencies: AmsDependencies, transition: str) ->
|
|
|
82
114
|
expected_config_version: int,
|
|
83
115
|
confirm: bool,
|
|
84
116
|
) -> None:
|
|
85
|
-
if not confirm:
|
|
86
|
-
raise click.UsageError("--confirm is required; no lifecycle write was sent.")
|
|
87
117
|
target_data = {
|
|
88
118
|
"environment": environment,
|
|
89
119
|
"tenant_id": tenant_id,
|
|
90
120
|
"agent_id": agent_id,
|
|
91
121
|
"expected_config_version": expected_config_version,
|
|
92
122
|
}
|
|
123
|
+
if not confirm:
|
|
124
|
+
_preview_then_refuse(
|
|
125
|
+
invocation,
|
|
126
|
+
f"agents.{transition}",
|
|
127
|
+
target_data,
|
|
128
|
+
lambda target: preview_lifecycle(
|
|
129
|
+
dependencies,
|
|
130
|
+
target,
|
|
131
|
+
agent_id,
|
|
132
|
+
transition=transition,
|
|
133
|
+
expected_config_version=expected_config_version,
|
|
134
|
+
),
|
|
135
|
+
"--confirm is required; no lifecycle write was sent. Re-run with --confirm to send it.",
|
|
136
|
+
login_hint=LOGIN_HINT,
|
|
137
|
+
)
|
|
93
138
|
|
|
94
139
|
def execute():
|
|
95
140
|
_require_login()
|
|
@@ -123,13 +168,21 @@ def create_delete_command(dependencies: AmsDependencies) -> click.Command:
|
|
|
123
168
|
"--confirm",
|
|
124
169
|
is_flag=True,
|
|
125
170
|
default=False,
|
|
126
|
-
help="Required acknowledgement of the printed target and disclosure block; without it
|
|
171
|
+
help="Required acknowledgement of the printed target and disclosure block; without it the command "
|
|
172
|
+
"prints both and sends nothing.",
|
|
127
173
|
)
|
|
128
174
|
@pass_ams
|
|
129
175
|
def command(invocation, environment: str | None, tenant_id: str | None, agent_id: str, confirm: bool) -> None:
|
|
130
|
-
if not confirm:
|
|
131
|
-
raise click.UsageError("--confirm is required; no delete was sent.")
|
|
132
176
|
target_data = {"environment": environment, "tenant_id": tenant_id, "agent_id": agent_id}
|
|
177
|
+
if not confirm:
|
|
178
|
+
_preview_then_refuse(
|
|
179
|
+
invocation,
|
|
180
|
+
"agents.delete",
|
|
181
|
+
target_data,
|
|
182
|
+
lambda target: preview_delete(dependencies, target, agent_id),
|
|
183
|
+
"--confirm is required; no delete was sent. Re-run with --confirm to send it.",
|
|
184
|
+
login_hint=DELETE_LOGIN_HINT,
|
|
185
|
+
)
|
|
133
186
|
|
|
134
187
|
def execute():
|
|
135
188
|
_require_login(DELETE_LOGIN_HINT)
|
|
@@ -221,7 +274,10 @@ CONFIG_VERSION_HELP = (
|
|
|
221
274
|
"The config_version read before the write. A local best-effort guard only: the route has no "
|
|
222
275
|
"If-Match, so it never proves atomicity."
|
|
223
276
|
)
|
|
224
|
-
CONFIRM_HELP =
|
|
277
|
+
CONFIRM_HELP = (
|
|
278
|
+
"Required acknowledgement of the target and the printed reviewed diff; without it the command prints "
|
|
279
|
+
"the diff and sends nothing."
|
|
280
|
+
)
|
|
225
281
|
|
|
226
282
|
|
|
227
283
|
def _assignment_changes(values: dict, cleared: dict) -> dict:
|
|
@@ -320,8 +376,6 @@ def create_assignments_set_command(dependencies: AmsDependencies) -> click.Comma
|
|
|
320
376
|
clear_data_source_ids: bool,
|
|
321
377
|
confirm: bool,
|
|
322
378
|
) -> None:
|
|
323
|
-
if not confirm:
|
|
324
|
-
raise click.UsageError("--confirm is required; no assignment write was sent.")
|
|
325
379
|
changes = _assignment_changes(
|
|
326
380
|
{
|
|
327
381
|
"department_id": department_id,
|
|
@@ -351,6 +405,21 @@ def create_assignments_set_command(dependencies: AmsDependencies) -> click.Comma
|
|
|
351
405
|
"expected_config_version": expected_config_version,
|
|
352
406
|
"changed_fields": sorted(changes),
|
|
353
407
|
}
|
|
408
|
+
if not confirm:
|
|
409
|
+
_preview_then_refuse(
|
|
410
|
+
invocation,
|
|
411
|
+
"agents.assignments.set",
|
|
412
|
+
target_data,
|
|
413
|
+
lambda target: preview_assignments(
|
|
414
|
+
dependencies,
|
|
415
|
+
target,
|
|
416
|
+
agent_id,
|
|
417
|
+
changes,
|
|
418
|
+
expected_config_version=expected_config_version,
|
|
419
|
+
),
|
|
420
|
+
"--confirm is required; no assignment write was sent. Re-run with --confirm to send it.",
|
|
421
|
+
login_hint=ASSIGNMENT_LOGIN_HINT,
|
|
422
|
+
)
|
|
354
423
|
|
|
355
424
|
def execute():
|
|
356
425
|
_require_login(ASSIGNMENT_LOGIN_HINT)
|