healthcloud-cli 3.2.5__tar.gz → 3.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.
- {healthcloud_cli-3.2.5 → healthcloud_cli-3.4.0}/PKG-INFO +146 -12
- {healthcloud_cli-3.2.5 → healthcloud_cli-3.4.0}/README.md +145 -11
- healthcloud_cli-3.4.0/healthcloud_cli/ams/agents/__init__.py +5 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/agents/commands.py +83 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/agents/group.py +18 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/agents/operations.py +72 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/agents/projections.py +37 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/auth.py +91 -0
- {healthcloud_cli-3.2.5 → healthcloud_cli-3.4.0}/healthcloud_cli/ams/commands.py +2 -0
- {healthcloud_cli-3.2.5 → healthcloud_cli-3.4.0}/healthcloud_cli/ams/compatibility.py +6 -4
- healthcloud_cli-3.4.0/healthcloud_cli/ams/context.py +212 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/departments/__init__.py +5 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/departments/commands.py +61 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/departments/group.py +18 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/departments/operations.py +71 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/departments/projections.py +19 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/domain_errors.py +9 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/errors.py +97 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/guardrails/__init__.py +5 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/guardrails/commands.py +57 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/guardrails/group.py +18 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/guardrails/operations.py +67 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/guardrails/projections.py +18 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/organization/__init__.py +5 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/organization/commands.py +29 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/organization/group.py +17 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/organization/operations.py +33 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/organization/projections.py +29 -0
- {healthcloud_cli-3.2.5 → healthcloud_cli-3.4.0}/healthcloud_cli/ams/output.py +17 -3
- healthcloud_cli-3.4.0/healthcloud_cli/ams/policies/__init__.py +5 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/policies/commands.py +57 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/policies/group.py +18 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/policies/operations.py +67 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/policies/projections.py +21 -0
- {healthcloud_cli-3.2.5 → healthcloud_cli-3.4.0}/healthcloud_cli/ams/registry.py +14 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/results.py +31 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/session.py +345 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/skills/__init__.py +5 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/skills/commands.py +57 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/skills/group.py +18 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/skills/operations.py +67 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/skills/projections.py +19 -0
- {healthcloud_cli-3.2.5 → healthcloud_cli-3.4.0}/healthcloud_cli/ams/target.py +14 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/teams/__init__.py +5 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/teams/commands.py +57 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/teams/group.py +18 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/teams/operations.py +67 -0
- healthcloud_cli-3.4.0/healthcloud_cli/ams/teams/projections.py +21 -0
- {healthcloud_cli-3.2.5 → healthcloud_cli-3.4.0}/healthcloud_cli/ams/windows_files.py +51 -2
- {healthcloud_cli-3.2.5 → healthcloud_cli-3.4.0}/healthcloud_cli/cli.py +61 -1
- {healthcloud_cli-3.2.5 → healthcloud_cli-3.4.0}/pyproject.toml +1 -1
- healthcloud_cli-3.2.5/healthcloud_cli/ams/auth.py +0 -49
- healthcloud_cli-3.2.5/healthcloud_cli/ams/context.py +0 -74
- {healthcloud_cli-3.2.5 → healthcloud_cli-3.4.0}/.gitignore +0 -0
- {healthcloud_cli-3.2.5 → healthcloud_cli-3.4.0}/hatch_build.py +0 -0
- {healthcloud_cli-3.2.5 → healthcloud_cli-3.4.0}/healthcloud_cli/__init__.py +0 -0
- {healthcloud_cli-3.2.5 → healthcloud_cli-3.4.0}/healthcloud_cli/ams/__init__.py +0 -0
- {healthcloud_cli-3.2.5 → healthcloud_cli-3.4.0}/healthcloud_cli/ams/group.py +0 -0
- {healthcloud_cli-3.2.5 → healthcloud_cli-3.4.0}/healthcloud_cli/ams/tuning.py +0 -0
- {healthcloud_cli-3.2.5 → healthcloud_cli-3.4.0}/healthcloud_cli/ams/ui.py +0 -0
- {healthcloud_cli-3.2.5 → healthcloud_cli-3.4.0}/healthcloud_cli/context.py +0 -0
- {healthcloud_cli-3.2.5 → healthcloud_cli-3.4.0}/healthcloud_cli/contracts/__init__.py +0 -0
- {healthcloud_cli-3.2.5 → healthcloud_cli-3.4.0}/healthcloud_cli/contracts/mcp-tools.manifest.json +0 -0
- {healthcloud_cli-3.2.5 → healthcloud_cli-3.4.0}/healthcloud_cli/main.py +0 -0
- {healthcloud_cli-3.2.5 → healthcloud_cli-3.4.0}/healthcloud_cli/manifest.py +0 -0
- {healthcloud_cli-3.2.5 → healthcloud_cli-3.4.0}/healthcloud_cli/output.py +0 -0
- {healthcloud_cli-3.2.5 → healthcloud_cli-3.4.0}/healthcloud_cli/params.py +0 -0
- {healthcloud_cli-3.2.5 → healthcloud_cli-3.4.0}/healthcloud_cli/util.py +0 -0
- {healthcloud_cli-3.2.5 → healthcloud_cli-3.4.0}/scripts/__init__.py +0 -0
- {healthcloud_cli-3.2.5 → healthcloud_cli-3.4.0}/scripts/bundle_manifest.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: healthcloud-cli
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.4.0
|
|
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
|
|
@@ -69,10 +69,10 @@ _HC_COMPLETE=bash_complete COMP_WORDS="hc ams inspect --o" COMP_CWORD=3 uv run -
|
|
|
69
69
|
```
|
|
70
70
|
|
|
71
71
|
Operational validation starts only when Click invokes an AMS leaf callback.
|
|
72
|
-
`discover`
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
those safety requirements.
|
|
72
|
+
`discover`, `agents`, `departments`, `teams`, `organization`, `skills`, and `policies` then
|
|
73
|
+
validate their explicit environment and tenant arguments; the remaining leaves
|
|
74
|
+
require `--target-file`. All apply the root, target, and authentication checks
|
|
75
|
+
described below. Deferring preflight does not relax those safety requirements.
|
|
76
76
|
|
|
77
77
|
The bundled tool manifest (`healthcloud_cli/contracts/mcp-tools.manifest.json`)
|
|
78
78
|
is a copy of `packages/cli/contracts/mcp-tools.manifest.json`. Re-sync it
|
|
@@ -280,13 +280,147 @@ uv sync --frozen --extra dev
|
|
|
280
280
|
uv run --frozen hc ams --help
|
|
281
281
|
```
|
|
282
282
|
|
|
283
|
-
|
|
284
|
-
|
|
283
|
+
Create one private tenant-admin session before interactive AMS work, inspect its
|
|
284
|
+
non-secret binding, and remove it when finished:
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
uv run --frozen hc login --environment dev --tenant-id TENANT_ID
|
|
288
|
+
uv run --frozen hc login --status
|
|
289
|
+
uv run --frozen hc logout
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
`hc login` reads `HC_AMS_ADMIN_EMAIL` and `HC_AMS_ADMIN_PASSWORD` when present,
|
|
293
|
+
otherwise it prompts (with hidden password input). It stores only the email,
|
|
294
|
+
tenant/environment binding, access/refresh tokens and expiry in the strict
|
|
295
|
+
owner-only `~/.healthcloud/cli/ams-session.json`; it never stores the password.
|
|
296
|
+
AMS commands may omit both target flags while this session is present, except
|
|
297
|
+
that a `prod` session still needs `--environment prod` on every command. Explicit
|
|
298
|
+
flags and target files must match it exactly. A session within 60 seconds of
|
|
299
|
+
expiry is refreshed once before the operation, under a lock so concurrent
|
|
300
|
+
commands never spend the same refresh token (a second command waits up to 30 seconds, then stops), and
|
|
301
|
+
atomically replaced. Refresh
|
|
302
|
+
failure stops without an AMS call or password fallback and asks for a new login.
|
|
303
|
+
If the refreshed session cannot be saved, the current command still finishes and
|
|
304
|
+
prints a warning to run `hc login` again.
|
|
305
|
+
|
|
306
|
+
`~/.healthcloud` and `~/.healthcloud/cli` must be directories you own with mode
|
|
307
|
+
700; the CLI creates them that way, and refuses (naming the directory and the
|
|
308
|
+
`chmod 700` fix) if an existing one is shared. `hc logout` deletes the local file
|
|
309
|
+
only and reports `"server_session_revoked": false`: issued tokens stay valid
|
|
310
|
+
until they expire.
|
|
311
|
+
|
|
312
|
+
Bootstrap candidate IDs with the public SDK discovery endpoint. Without a saved
|
|
313
|
+
session both flags are required; a saved session supplies both together. No MCP
|
|
314
|
+
defaults, admin login, or automatic candidate selection are used:
|
|
285
315
|
|
|
286
316
|
```bash
|
|
287
317
|
uv run --frozen hc ams discover --environment dev --tenant-id TENANT_ID
|
|
288
318
|
```
|
|
289
319
|
|
|
320
|
+
Read-only agent listing, inspection and export take flags instead of a target
|
|
321
|
+
file; both may be omitted together when a matching saved session exists. Without
|
|
322
|
+
one, they log in as tenant admin using `HC_AMS_ADMIN_EMAIL` /
|
|
323
|
+
`HC_AMS_ADMIN_PASSWORD`. Stdout carries bounded metadata only; `adapter` shows
|
|
324
|
+
whether an agent runs from the `file` or `db` config adapter (`unknown` when the
|
|
325
|
+
server does not say). `export` first re-checks the agent/tenant identity, then
|
|
326
|
+
saves the server's own JSON/YAML export byte-for-byte to a new owner-only `--out`
|
|
327
|
+
file, refusing (and leaving no file) when the body is not valid UTF-8. `export`
|
|
328
|
+
needs an AMS build that serves `/agents/{agent_id}/configuration/export`; that
|
|
329
|
+
route is not yet deployed to dev:
|
|
330
|
+
|
|
331
|
+
```bash
|
|
332
|
+
uv run --frozen hc ams agents list --environment dev --tenant-id TENANT_ID
|
|
333
|
+
uv run --frozen hc ams agents get --environment dev --tenant-id TENANT_ID --agent-id AGENT_ID
|
|
334
|
+
uv run --frozen hc ams agents export --environment dev --tenant-id TENANT_ID --agent-id AGENT_ID \
|
|
335
|
+
--format yaml --out agent.yaml
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
Read-only department listing and inspection use the same explicit tenant-admin
|
|
339
|
+
targeting. They emit one versioned JSON result on stdout; failures emit one
|
|
340
|
+
categorized JSON result on stderr. Department descriptions, creator identities,
|
|
341
|
+
and evaluation-suite content are never included in the projection:
|
|
342
|
+
|
|
343
|
+
```bash
|
|
344
|
+
uv run --frozen hc ams departments list --environment dev --tenant-id TENANT_ID
|
|
345
|
+
uv run --frozen hc ams departments get --environment dev --tenant-id TENANT_ID \
|
|
346
|
+
--department-id DEPARTMENT_ID
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
Department reads are complete and unpaged. The CLI does not expose department
|
|
350
|
+
create, update, delete, activate, or deactivate operations.
|
|
351
|
+
|
|
352
|
+
Read-only team listing and inspection are also complete and unpaged. The bounded
|
|
353
|
+
projection omits descriptions and creator identities; it includes evaluation-suite
|
|
354
|
+
IDs but never suite content. The CLI does not expose team mutations:
|
|
355
|
+
|
|
356
|
+
```bash
|
|
357
|
+
uv run --frozen hc ams teams list --environment dev --tenant-id TENANT_ID
|
|
358
|
+
uv run --frozen hc ams teams get --environment dev --tenant-id TENANT_ID --team-id TEAM_ID
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
The organization hierarchy is the backend-built department/team/agent tree. The
|
|
362
|
+
CLI preserves its order and nesting without issuing entity reads, joining records,
|
|
363
|
+
or inferring missing relationships:
|
|
364
|
+
|
|
365
|
+
```bash
|
|
366
|
+
uv run --frozen hc ams organization hierarchy --environment dev --tenant-id TENANT_ID
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
Read-only skill catalog listing and inspection are complete and unpaged. The
|
|
370
|
+
bounded projection includes only skill IDs, names, tool IDs, and audit timestamps;
|
|
371
|
+
it omits descriptions, tenant identity, creator identity, arbitrary response
|
|
372
|
+
fields, and tool details. Tool-ID order is preserved:
|
|
373
|
+
|
|
374
|
+
```bash
|
|
375
|
+
uv run --frozen hc ams skills list --environment dev --tenant-id TENANT_ID
|
|
376
|
+
uv run --frozen hc ams skills get --environment dev --tenant-id TENANT_ID --skill-id SKILL_ID
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
The CLI does not create, update, delete, or assign skills. Skill commands do not
|
|
380
|
+
read guardrails. They make exactly one catalog GET after tenant-admin login
|
|
381
|
+
and does not paginate, retry, cache, join, or infer additional catalog data.
|
|
382
|
+
Skill reads refuse target files, root credentials or base URLs, raw output,
|
|
383
|
+
blank or dot-segment skill IDs, and installed SDKs that do not provide both
|
|
384
|
+
skill list and get methods. These local refusals happen before tenant-admin login
|
|
385
|
+
or catalog reads.
|
|
386
|
+
|
|
387
|
+
Read-only policy catalog listing and inspection are complete and unpaged. The
|
|
388
|
+
bounded projection includes only policy IDs, names, department IDs, guardrail
|
|
389
|
+
IDs, active status, and audit timestamps. It never emits protected policy
|
|
390
|
+
content, descriptions, tenant or creator identity, arbitrary response fields,
|
|
391
|
+
or joined department/guardrail details. Guardrail-ID order is preserved:
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
uv run --frozen hc ams policies list --environment dev --tenant-id TENANT_ID
|
|
395
|
+
uv run --frozen hc ams policies get --environment dev --tenant-id TENANT_ID --policy-id POLICY_ID
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
The CLI does not export protected policy content; create, update, delete, or
|
|
399
|
+
assign policies; or join guardrail records. It makes exactly one catalog GET after
|
|
400
|
+
tenant-admin login and does not paginate, retry, cache, join, or infer referenced
|
|
401
|
+
resources. Policy reads refuse target files, root credentials or base URLs, raw
|
|
402
|
+
output, blank or dot-segment policy IDs, and installed SDKs without both policy
|
|
403
|
+
methods before tenant-admin login or catalog reads. Successful reads make no
|
|
404
|
+
assignment, deployment, serving, enforcement, or effectiveness claim.
|
|
405
|
+
|
|
406
|
+
Read-only guardrail catalog listing and inspection are complete and unpaged.
|
|
407
|
+
The bounded projection includes only guardrail IDs, names, and audit timestamps.
|
|
408
|
+
It never emits protected rules, descriptions, tenant or creator identity,
|
|
409
|
+
arbitrary response fields, or joined policy/agent details:
|
|
410
|
+
|
|
411
|
+
```bash
|
|
412
|
+
uv run --frozen hc ams guardrails list --environment dev --tenant-id TENANT_ID
|
|
413
|
+
uv run --frozen hc ams guardrails get --environment dev --tenant-id TENANT_ID \
|
|
414
|
+
--guardrail-id GUARDRAIL_ID
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
The CLI does not export rules; create, update, delete, assign, deploy, or enforce
|
|
418
|
+
guardrails; or claim they are active or effective. It makes exactly one catalog
|
|
419
|
+
GET after tenant-admin login and does not paginate, retry, cache, join, or infer
|
|
420
|
+
additional data. Guardrail reads refuse target files, root credentials or base
|
|
421
|
+
URLs, raw output, blank or dot-segment guardrail IDs, and installed SDKs without
|
|
422
|
+
both guardrail methods before tenant-admin login or catalog reads.
|
|
423
|
+
|
|
290
424
|
Every other command requires an explicit local, non-secret target JSON file.
|
|
291
425
|
Only the canonical HTTPS AMS origin for that environment is accepted; custom
|
|
292
426
|
origins require separately verified support. Target and nested qualification keys
|
|
@@ -355,11 +489,11 @@ configuration and recheck it before apply and selected-field restore. This is an
|
|
|
355
489
|
operator prerequisite: the current CLI does not automatically attest deployment
|
|
356
490
|
or all-writer coverage, and the record adds no server authorization boundary.
|
|
357
491
|
|
|
358
|
-
|
|
359
|
-
in the current process, intended
|
|
360
|
-
`onepassword-env` wrapper
|
|
361
|
-
|
|
362
|
-
|
|
492
|
+
For CI and scripts with no saved session, credentials may still enter through
|
|
493
|
+
`HC_AMS_ADMIN_EMAIL` and `HC_AMS_ADMIN_PASSWORD` in the current process, intended
|
|
494
|
+
for composition with the existing `onepassword-env` wrapper; that compatibility
|
|
495
|
+
path logs in once per invocation. There is no fallback identity, secret argument,
|
|
496
|
+
arbitrary token import, resolved env file, keychain, or browser credential bridge. Root MCP
|
|
363
497
|
`--access-token`, `--base-url`, their environment equivalents, and token/base-URL
|
|
364
498
|
profiles are refused for AMS. Root profile environment values do not select AMS.
|
|
365
499
|
|
|
@@ -51,10 +51,10 @@ _HC_COMPLETE=bash_complete COMP_WORDS="hc ams inspect --o" COMP_CWORD=3 uv run -
|
|
|
51
51
|
```
|
|
52
52
|
|
|
53
53
|
Operational validation starts only when Click invokes an AMS leaf callback.
|
|
54
|
-
`discover`
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
those safety requirements.
|
|
54
|
+
`discover`, `agents`, `departments`, `teams`, `organization`, `skills`, and `policies` then
|
|
55
|
+
validate their explicit environment and tenant arguments; the remaining leaves
|
|
56
|
+
require `--target-file`. All apply the root, target, and authentication checks
|
|
57
|
+
described below. Deferring preflight does not relax those safety requirements.
|
|
58
58
|
|
|
59
59
|
The bundled tool manifest (`healthcloud_cli/contracts/mcp-tools.manifest.json`)
|
|
60
60
|
is a copy of `packages/cli/contracts/mcp-tools.manifest.json`. Re-sync it
|
|
@@ -262,13 +262,147 @@ uv sync --frozen --extra dev
|
|
|
262
262
|
uv run --frozen hc ams --help
|
|
263
263
|
```
|
|
264
264
|
|
|
265
|
-
|
|
266
|
-
|
|
265
|
+
Create one private tenant-admin session before interactive AMS work, inspect its
|
|
266
|
+
non-secret binding, and remove it when finished:
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
uv run --frozen hc login --environment dev --tenant-id TENANT_ID
|
|
270
|
+
uv run --frozen hc login --status
|
|
271
|
+
uv run --frozen hc logout
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
`hc login` reads `HC_AMS_ADMIN_EMAIL` and `HC_AMS_ADMIN_PASSWORD` when present,
|
|
275
|
+
otherwise it prompts (with hidden password input). It stores only the email,
|
|
276
|
+
tenant/environment binding, access/refresh tokens and expiry in the strict
|
|
277
|
+
owner-only `~/.healthcloud/cli/ams-session.json`; it never stores the password.
|
|
278
|
+
AMS commands may omit both target flags while this session is present, except
|
|
279
|
+
that a `prod` session still needs `--environment prod` on every command. Explicit
|
|
280
|
+
flags and target files must match it exactly. A session within 60 seconds of
|
|
281
|
+
expiry is refreshed once before the operation, under a lock so concurrent
|
|
282
|
+
commands never spend the same refresh token (a second command waits up to 30 seconds, then stops), and
|
|
283
|
+
atomically replaced. Refresh
|
|
284
|
+
failure stops without an AMS call or password fallback and asks for a new login.
|
|
285
|
+
If the refreshed session cannot be saved, the current command still finishes and
|
|
286
|
+
prints a warning to run `hc login` again.
|
|
287
|
+
|
|
288
|
+
`~/.healthcloud` and `~/.healthcloud/cli` must be directories you own with mode
|
|
289
|
+
700; the CLI creates them that way, and refuses (naming the directory and the
|
|
290
|
+
`chmod 700` fix) if an existing one is shared. `hc logout` deletes the local file
|
|
291
|
+
only and reports `"server_session_revoked": false`: issued tokens stay valid
|
|
292
|
+
until they expire.
|
|
293
|
+
|
|
294
|
+
Bootstrap candidate IDs with the public SDK discovery endpoint. Without a saved
|
|
295
|
+
session both flags are required; a saved session supplies both together. No MCP
|
|
296
|
+
defaults, admin login, or automatic candidate selection are used:
|
|
267
297
|
|
|
268
298
|
```bash
|
|
269
299
|
uv run --frozen hc ams discover --environment dev --tenant-id TENANT_ID
|
|
270
300
|
```
|
|
271
301
|
|
|
302
|
+
Read-only agent listing, inspection and export take flags instead of a target
|
|
303
|
+
file; both may be omitted together when a matching saved session exists. Without
|
|
304
|
+
one, they log in as tenant admin using `HC_AMS_ADMIN_EMAIL` /
|
|
305
|
+
`HC_AMS_ADMIN_PASSWORD`. Stdout carries bounded metadata only; `adapter` shows
|
|
306
|
+
whether an agent runs from the `file` or `db` config adapter (`unknown` when the
|
|
307
|
+
server does not say). `export` first re-checks the agent/tenant identity, then
|
|
308
|
+
saves the server's own JSON/YAML export byte-for-byte to a new owner-only `--out`
|
|
309
|
+
file, refusing (and leaving no file) when the body is not valid UTF-8. `export`
|
|
310
|
+
needs an AMS build that serves `/agents/{agent_id}/configuration/export`; that
|
|
311
|
+
route is not yet deployed to dev:
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
uv run --frozen hc ams agents list --environment dev --tenant-id TENANT_ID
|
|
315
|
+
uv run --frozen hc ams agents get --environment dev --tenant-id TENANT_ID --agent-id AGENT_ID
|
|
316
|
+
uv run --frozen hc ams agents export --environment dev --tenant-id TENANT_ID --agent-id AGENT_ID \
|
|
317
|
+
--format yaml --out agent.yaml
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Read-only department listing and inspection use the same explicit tenant-admin
|
|
321
|
+
targeting. They emit one versioned JSON result on stdout; failures emit one
|
|
322
|
+
categorized JSON result on stderr. Department descriptions, creator identities,
|
|
323
|
+
and evaluation-suite content are never included in the projection:
|
|
324
|
+
|
|
325
|
+
```bash
|
|
326
|
+
uv run --frozen hc ams departments list --environment dev --tenant-id TENANT_ID
|
|
327
|
+
uv run --frozen hc ams departments get --environment dev --tenant-id TENANT_ID \
|
|
328
|
+
--department-id DEPARTMENT_ID
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
Department reads are complete and unpaged. The CLI does not expose department
|
|
332
|
+
create, update, delete, activate, or deactivate operations.
|
|
333
|
+
|
|
334
|
+
Read-only team listing and inspection are also complete and unpaged. The bounded
|
|
335
|
+
projection omits descriptions and creator identities; it includes evaluation-suite
|
|
336
|
+
IDs but never suite content. The CLI does not expose team mutations:
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
uv run --frozen hc ams teams list --environment dev --tenant-id TENANT_ID
|
|
340
|
+
uv run --frozen hc ams teams get --environment dev --tenant-id TENANT_ID --team-id TEAM_ID
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
The organization hierarchy is the backend-built department/team/agent tree. The
|
|
344
|
+
CLI preserves its order and nesting without issuing entity reads, joining records,
|
|
345
|
+
or inferring missing relationships:
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
uv run --frozen hc ams organization hierarchy --environment dev --tenant-id TENANT_ID
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
Read-only skill catalog listing and inspection are complete and unpaged. The
|
|
352
|
+
bounded projection includes only skill IDs, names, tool IDs, and audit timestamps;
|
|
353
|
+
it omits descriptions, tenant identity, creator identity, arbitrary response
|
|
354
|
+
fields, and tool details. Tool-ID order is preserved:
|
|
355
|
+
|
|
356
|
+
```bash
|
|
357
|
+
uv run --frozen hc ams skills list --environment dev --tenant-id TENANT_ID
|
|
358
|
+
uv run --frozen hc ams skills get --environment dev --tenant-id TENANT_ID --skill-id SKILL_ID
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
The CLI does not create, update, delete, or assign skills. Skill commands do not
|
|
362
|
+
read guardrails. They make exactly one catalog GET after tenant-admin login
|
|
363
|
+
and does not paginate, retry, cache, join, or infer additional catalog data.
|
|
364
|
+
Skill reads refuse target files, root credentials or base URLs, raw output,
|
|
365
|
+
blank or dot-segment skill IDs, and installed SDKs that do not provide both
|
|
366
|
+
skill list and get methods. These local refusals happen before tenant-admin login
|
|
367
|
+
or catalog reads.
|
|
368
|
+
|
|
369
|
+
Read-only policy catalog listing and inspection are complete and unpaged. The
|
|
370
|
+
bounded projection includes only policy IDs, names, department IDs, guardrail
|
|
371
|
+
IDs, active status, and audit timestamps. It never emits protected policy
|
|
372
|
+
content, descriptions, tenant or creator identity, arbitrary response fields,
|
|
373
|
+
or joined department/guardrail details. Guardrail-ID order is preserved:
|
|
374
|
+
|
|
375
|
+
```bash
|
|
376
|
+
uv run --frozen hc ams policies list --environment dev --tenant-id TENANT_ID
|
|
377
|
+
uv run --frozen hc ams policies get --environment dev --tenant-id TENANT_ID --policy-id POLICY_ID
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
The CLI does not export protected policy content; create, update, delete, or
|
|
381
|
+
assign policies; or join guardrail records. It makes exactly one catalog GET after
|
|
382
|
+
tenant-admin login and does not paginate, retry, cache, join, or infer referenced
|
|
383
|
+
resources. Policy reads refuse target files, root credentials or base URLs, raw
|
|
384
|
+
output, blank or dot-segment policy IDs, and installed SDKs without both policy
|
|
385
|
+
methods before tenant-admin login or catalog reads. Successful reads make no
|
|
386
|
+
assignment, deployment, serving, enforcement, or effectiveness claim.
|
|
387
|
+
|
|
388
|
+
Read-only guardrail catalog listing and inspection are complete and unpaged.
|
|
389
|
+
The bounded projection includes only guardrail IDs, names, and audit timestamps.
|
|
390
|
+
It never emits protected rules, descriptions, tenant or creator identity,
|
|
391
|
+
arbitrary response fields, or joined policy/agent details:
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
uv run --frozen hc ams guardrails list --environment dev --tenant-id TENANT_ID
|
|
395
|
+
uv run --frozen hc ams guardrails get --environment dev --tenant-id TENANT_ID \
|
|
396
|
+
--guardrail-id GUARDRAIL_ID
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
The CLI does not export rules; create, update, delete, assign, deploy, or enforce
|
|
400
|
+
guardrails; or claim they are active or effective. It makes exactly one catalog
|
|
401
|
+
GET after tenant-admin login and does not paginate, retry, cache, join, or infer
|
|
402
|
+
additional data. Guardrail reads refuse target files, root credentials or base
|
|
403
|
+
URLs, raw output, blank or dot-segment guardrail IDs, and installed SDKs without
|
|
404
|
+
both guardrail methods before tenant-admin login or catalog reads.
|
|
405
|
+
|
|
272
406
|
Every other command requires an explicit local, non-secret target JSON file.
|
|
273
407
|
Only the canonical HTTPS AMS origin for that environment is accepted; custom
|
|
274
408
|
origins require separately verified support. Target and nested qualification keys
|
|
@@ -337,11 +471,11 @@ configuration and recheck it before apply and selected-field restore. This is an
|
|
|
337
471
|
operator prerequisite: the current CLI does not automatically attest deployment
|
|
338
472
|
or all-writer coverage, and the record adds no server authorization boundary.
|
|
339
473
|
|
|
340
|
-
|
|
341
|
-
in the current process, intended
|
|
342
|
-
`onepassword-env` wrapper
|
|
343
|
-
|
|
344
|
-
|
|
474
|
+
For CI and scripts with no saved session, credentials may still enter through
|
|
475
|
+
`HC_AMS_ADMIN_EMAIL` and `HC_AMS_ADMIN_PASSWORD` in the current process, intended
|
|
476
|
+
for composition with the existing `onepassword-env` wrapper; that compatibility
|
|
477
|
+
path logs in once per invocation. There is no fallback identity, secret argument,
|
|
478
|
+
arbitrary token import, resolved env file, keychain, or browser credential bridge. Root MCP
|
|
345
479
|
`--access-token`, `--base-url`, their environment equivalents, and token/base-URL
|
|
346
480
|
profiles are refused for AMS. Root profile environment values do not select AMS.
|
|
347
481
|
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""Fresh Click adapters for read-only agent operations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import click
|
|
8
|
+
|
|
9
|
+
from ..compatibility import safe_errors
|
|
10
|
+
from ..context import AmsDependencies, pass_ams, preflight_agents
|
|
11
|
+
from ..output import metadata
|
|
12
|
+
from ..session import resolve_tenant_target
|
|
13
|
+
from .operations import AgentReadRefused, export_agent, get_agent, list_agents
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _environment(function):
|
|
17
|
+
return click.option("--environment", type=click.Choice(["dev", "uat", "prod"]))(function)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _tenant(function):
|
|
21
|
+
return click.option("--tenant-id")(function)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _agent(function):
|
|
25
|
+
return click.option("--agent-id", required=True)(function)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _run(operation, *args):
|
|
29
|
+
try:
|
|
30
|
+
return operation(*args)
|
|
31
|
+
except AgentReadRefused as exc:
|
|
32
|
+
raise click.ClickException(str(exc)) from None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def create_list_command(dependencies: AmsDependencies) -> click.Command:
|
|
36
|
+
@click.command("list")
|
|
37
|
+
@_environment
|
|
38
|
+
@_tenant
|
|
39
|
+
@pass_ams
|
|
40
|
+
@safe_errors
|
|
41
|
+
def command(invocation, environment: str | None, tenant_id: str | None) -> None:
|
|
42
|
+
preflight_agents(invocation)
|
|
43
|
+
metadata(_run(list_agents, dependencies, resolve_tenant_target(environment, tenant_id)))
|
|
44
|
+
|
|
45
|
+
return command
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def create_get_command(dependencies: AmsDependencies) -> click.Command:
|
|
49
|
+
@click.command("get")
|
|
50
|
+
@_environment
|
|
51
|
+
@_tenant
|
|
52
|
+
@_agent
|
|
53
|
+
@pass_ams
|
|
54
|
+
@safe_errors
|
|
55
|
+
def command(invocation, environment: str | None, tenant_id: str | None, agent_id: str) -> None:
|
|
56
|
+
preflight_agents(invocation)
|
|
57
|
+
metadata(_run(get_agent, dependencies, resolve_tenant_target(environment, tenant_id), agent_id))
|
|
58
|
+
|
|
59
|
+
return command
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def create_export_command(dependencies: AmsDependencies) -> click.Command:
|
|
63
|
+
@click.command("export")
|
|
64
|
+
@_environment
|
|
65
|
+
@_tenant
|
|
66
|
+
@_agent
|
|
67
|
+
@click.option("--out", required=True, type=click.Path(path_type=Path, dir_okay=False))
|
|
68
|
+
@click.option("--format", "export_format", type=click.Choice(["json", "yaml"]), default="json", show_default=True)
|
|
69
|
+
@pass_ams
|
|
70
|
+
@safe_errors
|
|
71
|
+
def command(
|
|
72
|
+
invocation,
|
|
73
|
+
environment: str | None,
|
|
74
|
+
tenant_id: str | None,
|
|
75
|
+
agent_id: str,
|
|
76
|
+
out: Path,
|
|
77
|
+
export_format: str,
|
|
78
|
+
) -> None:
|
|
79
|
+
preflight_agents(invocation)
|
|
80
|
+
target = resolve_tenant_target(environment, tenant_id)
|
|
81
|
+
metadata(_run(export_agent, dependencies, target, agent_id, out, export_format))
|
|
82
|
+
|
|
83
|
+
return command
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Fresh agent-domain group assembly."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
|
|
7
|
+
from ..context import AmsDependencies
|
|
8
|
+
from .commands import create_export_command, create_get_command, create_list_command
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def create_agents_group(dependencies: AmsDependencies) -> click.Group:
|
|
12
|
+
@click.group("agents")
|
|
13
|
+
def group() -> None:
|
|
14
|
+
"""Read-only agent listing, inspection and export for one explicit tenant."""
|
|
15
|
+
|
|
16
|
+
for factory in (create_list_command, create_get_command, create_export_command):
|
|
17
|
+
group.add_command(factory(dependencies))
|
|
18
|
+
return group
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""Click-free orchestration for agent list, get, and exact-text export."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import hashlib
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Literal
|
|
8
|
+
|
|
9
|
+
from ..context import AmsDependencies
|
|
10
|
+
from ..output import private_text_output
|
|
11
|
+
from ..target import TenantTarget
|
|
12
|
+
from .projections import detail, summary
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class AgentReadRefused(ValueError):
|
|
16
|
+
"""A stable refusal safe for the CLI adapter to expose."""
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _agent_id(value: str) -> str:
|
|
20
|
+
if not isinstance(value, str) or not value.strip():
|
|
21
|
+
raise AgentReadRefused("Explicit agent ID required.")
|
|
22
|
+
return value
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def list_agents(dependencies: AmsDependencies, target: TenantTarget) -> dict:
|
|
26
|
+
with dependencies.authenticated_sdk_factory(target) as sdk:
|
|
27
|
+
agents = sdk.ams_admin.list_agents()
|
|
28
|
+
if any(agent.tenant_id != target.tenant_id for agent in agents):
|
|
29
|
+
raise AgentReadRefused("Agent/tenant identity mismatch; stopped.")
|
|
30
|
+
return {
|
|
31
|
+
"environment": target.environment,
|
|
32
|
+
"tenant_id": target.tenant_id,
|
|
33
|
+
"agents": [summary(agent) for agent in agents],
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _verified_agent(sdk, target: TenantTarget, agent_id: str):
|
|
38
|
+
agent = sdk.ams_admin.get_agent(agent_id)
|
|
39
|
+
if agent is None or agent.id != agent_id or agent.tenant_id != target.tenant_id:
|
|
40
|
+
raise AgentReadRefused("Agent/tenant identity mismatch; stopped.")
|
|
41
|
+
return agent
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def get_agent(dependencies: AmsDependencies, target: TenantTarget, agent_id: str) -> dict:
|
|
45
|
+
agent_id = _agent_id(agent_id)
|
|
46
|
+
with dependencies.authenticated_sdk_factory(target) as sdk:
|
|
47
|
+
agent = _verified_agent(sdk, target, agent_id)
|
|
48
|
+
return {"environment": target.environment, "tenant_id": target.tenant_id} | detail(agent)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def export_agent(
|
|
52
|
+
dependencies: AmsDependencies,
|
|
53
|
+
target: TenantTarget,
|
|
54
|
+
agent_id: str,
|
|
55
|
+
output: Path,
|
|
56
|
+
export_format: Literal["json", "yaml"],
|
|
57
|
+
) -> dict:
|
|
58
|
+
agent_id = _agent_id(agent_id)
|
|
59
|
+
if export_format not in ("json", "yaml"):
|
|
60
|
+
raise AgentReadRefused("Export format must be json or yaml.")
|
|
61
|
+
with private_text_output(output) as write, dependencies.authenticated_sdk_factory(target) as sdk:
|
|
62
|
+
_verified_agent(sdk, target, agent_id)
|
|
63
|
+
text = sdk.ams_admin.export_agent_configuration(agent_id, format=export_format)
|
|
64
|
+
write(text)
|
|
65
|
+
return {
|
|
66
|
+
"environment": target.environment,
|
|
67
|
+
"tenant_id": target.tenant_id,
|
|
68
|
+
"agent_id": agent_id,
|
|
69
|
+
"path": str(output),
|
|
70
|
+
"format": export_format,
|
|
71
|
+
"sha256": hashlib.sha256(text.encode("utf-8")).hexdigest(),
|
|
72
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Explicit bounded projections for agent reads."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from healthcloud.models.ams_tuning import AgentConfig
|
|
6
|
+
|
|
7
|
+
from ..output import digest
|
|
8
|
+
|
|
9
|
+
ASSIGNED_REFERENCES = ("tool_ids", "skill_ids", "guardrail_ids", "policy_ids", "data_source_ids")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _metadata_string(value: object) -> str:
|
|
13
|
+
return value if isinstance(value, str) and value.strip() else "unknown"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def summary(agent: AgentConfig) -> dict:
|
|
17
|
+
runtime = agent.runtime_configuration if isinstance(agent.runtime_configuration, dict) else {}
|
|
18
|
+
return {
|
|
19
|
+
"id": agent.id,
|
|
20
|
+
"name": agent.name,
|
|
21
|
+
"key": agent.key,
|
|
22
|
+
"type": agent.type,
|
|
23
|
+
"status": agent.status,
|
|
24
|
+
"active": agent.active,
|
|
25
|
+
"config_version": agent.config_version,
|
|
26
|
+
"adapter": _metadata_string(runtime.get("adapter")),
|
|
27
|
+
"runtime": _metadata_string(runtime.get("runtime")),
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def detail(agent: AgentConfig) -> dict:
|
|
32
|
+
values = {"instructions": agent.instructions, "greetings": agent.greetings}
|
|
33
|
+
return summary(agent) | {
|
|
34
|
+
"fields": sorted(values),
|
|
35
|
+
"field_hashes": {key: digest(value) for key, value in values.items()},
|
|
36
|
+
"assigned_references": {key: getattr(agent, key) for key in ASSIGNED_REFERENCES},
|
|
37
|
+
}
|