healthcloud-cli 3.10.2__tar.gz → 3.10.4__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.
Files changed (143) hide show
  1. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/PKG-INFO +12 -7
  2. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/README.md +11 -6
  3. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/agent_files/commands.py +1 -1
  4. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/agent_files/operations.py +10 -5
  5. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/util.py +21 -16
  6. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/pyproject.toml +1 -1
  7. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/.gitignore +0 -0
  8. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/hatch_build.py +0 -0
  9. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/__init__.py +0 -0
  10. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/admins/__init__.py +0 -0
  11. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/admins/commands.py +0 -0
  12. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/admins/group.py +0 -0
  13. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/admins/operations.py +0 -0
  14. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/__init__.py +0 -0
  15. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/actions/__init__.py +0 -0
  16. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/actions/commands.py +0 -0
  17. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/actions/group.py +0 -0
  18. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/actions/operations.py +0 -0
  19. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/actions/projections.py +0 -0
  20. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/agent_files/__init__.py +0 -0
  21. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/agent_files/group.py +0 -0
  22. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/agent_files/projections.py +0 -0
  23. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/agent_logs/__init__.py +0 -0
  24. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/agent_logs/commands.py +0 -0
  25. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/agent_logs/group.py +0 -0
  26. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/agent_logs/operations.py +0 -0
  27. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/agent_logs/projections.py +0 -0
  28. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/agents/__init__.py +0 -0
  29. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/agents/commands.py +0 -0
  30. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/agents/group.py +0 -0
  31. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/agents/operations.py +0 -0
  32. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/agents/projections.py +0 -0
  33. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/audit/__init__.py +0 -0
  34. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/audit/commands.py +0 -0
  35. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/audit/operations.py +0 -0
  36. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/audit/projections.py +0 -0
  37. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/auth.py +0 -0
  38. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/commands.py +0 -0
  39. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/compatibility.py +0 -0
  40. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/context.py +0 -0
  41. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/dashboard/__init__.py +0 -0
  42. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/dashboard/commands.py +0 -0
  43. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/dashboard/operations.py +0 -0
  44. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/dashboard/projections.py +0 -0
  45. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/data_sources/__init__.py +0 -0
  46. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/data_sources/commands.py +0 -0
  47. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/data_sources/group.py +0 -0
  48. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/data_sources/operations.py +0 -0
  49. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/data_sources/projections.py +0 -0
  50. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/departments/__init__.py +0 -0
  51. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/departments/commands.py +0 -0
  52. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/departments/group.py +0 -0
  53. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/departments/operations.py +0 -0
  54. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/departments/projections.py +0 -0
  55. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/domain_errors.py +0 -0
  56. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/endpoint.py +0 -0
  57. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/errors.py +0 -0
  58. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/group.py +0 -0
  59. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/guardrails/__init__.py +0 -0
  60. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/guardrails/commands.py +0 -0
  61. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/guardrails/group.py +0 -0
  62. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/guardrails/operations.py +0 -0
  63. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/guardrails/projections.py +0 -0
  64. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/health_services/__init__.py +0 -0
  65. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/health_services/commands.py +0 -0
  66. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/health_services/group.py +0 -0
  67. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/health_services/operations.py +0 -0
  68. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/health_services/projections.py +0 -0
  69. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/operations/__init__.py +0 -0
  70. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/operations/commands.py +0 -0
  71. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/operations/group.py +0 -0
  72. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/operations/operations.py +0 -0
  73. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/operations/projections.py +0 -0
  74. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/organization/__init__.py +0 -0
  75. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/organization/commands.py +0 -0
  76. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/organization/group.py +0 -0
  77. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/organization/operations.py +0 -0
  78. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/organization/projections.py +0 -0
  79. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/output.py +0 -0
  80. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/paging.py +0 -0
  81. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/policies/__init__.py +0 -0
  82. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/policies/commands.py +0 -0
  83. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/policies/group.py +0 -0
  84. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/policies/operations.py +0 -0
  85. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/policies/projections.py +0 -0
  86. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/pretty.py +0 -0
  87. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/registry.py +0 -0
  88. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/results.py +0 -0
  89. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/runs/__init__.py +0 -0
  90. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/runs/commands.py +0 -0
  91. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/runs/group.py +0 -0
  92. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/runs/operations.py +0 -0
  93. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/runs/projections.py +0 -0
  94. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/schedules/__init__.py +0 -0
  95. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/schedules/commands.py +0 -0
  96. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/schedules/cron.py +0 -0
  97. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/schedules/group.py +0 -0
  98. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/schedules/operations.py +0 -0
  99. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/schedules/projections.py +0 -0
  100. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/session.py +0 -0
  101. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/sessions/__init__.py +0 -0
  102. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/sessions/commands.py +0 -0
  103. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/sessions/group.py +0 -0
  104. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/sessions/operations.py +0 -0
  105. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/sessions/projections.py +0 -0
  106. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/skills/__init__.py +0 -0
  107. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/skills/commands.py +0 -0
  108. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/skills/group.py +0 -0
  109. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/skills/operations.py +0 -0
  110. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/skills/projections.py +0 -0
  111. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/target.py +0 -0
  112. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/teams/__init__.py +0 -0
  113. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/teams/commands.py +0 -0
  114. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/teams/group.py +0 -0
  115. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/teams/operations.py +0 -0
  116. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/teams/projections.py +0 -0
  117. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/tools/__init__.py +0 -0
  118. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/tools/commands.py +0 -0
  119. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/tools/group.py +0 -0
  120. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/tools/operations.py +0 -0
  121. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/tools/projections.py +0 -0
  122. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/tuning.py +0 -0
  123. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/ui.py +0 -0
  124. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/usage/__init__.py +0 -0
  125. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/usage/commands.py +0 -0
  126. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/usage/group.py +0 -0
  127. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/usage/operations.py +0 -0
  128. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/usage/projections.py +0 -0
  129. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/ams/windows_files.py +0 -0
  130. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/cli.py +0 -0
  131. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/context.py +0 -0
  132. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/contracts/__init__.py +0 -0
  133. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/contracts/mcp-tools.manifest.json +0 -0
  134. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/main.py +0 -0
  135. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/manifest.py +0 -0
  136. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/output.py +0 -0
  137. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/params.py +0 -0
  138. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/tenants/__init__.py +0 -0
  139. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/tenants/commands.py +0 -0
  140. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/tenants/group.py +0 -0
  141. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/healthcloud_cli/tenants/operations.py +0 -0
  142. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/scripts/__init__.py +0 -0
  143. {healthcloud_cli-3.10.2 → healthcloud_cli-3.10.4}/scripts/bundle_manifest.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: healthcloud-cli
3
- Version: 3.10.2
3
+ Version: 3.10.4
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
@@ -369,7 +369,7 @@ for `login`/`--status`, and `{"schema_version": 1, "ok": true, "removed":
369
369
  true|false, "server_session_revoked": false}` for `logout`.
370
370
 
371
371
  For CI and agents, log in non-interactively: pass `--email` and pipe the password
372
- to `--password-stdin` (read as exactly one stdin line, never echoed, never a
372
+ to `--password-stdin` (read as exactly one stdin line, never printed by the CLI, never a
373
373
  flag value — there is no `--password` option):
374
374
 
375
375
  ```bash
@@ -389,9 +389,13 @@ prompt (no `GetPassWarning`, no echoed password); a missing email on a
389
389
  non-interactive stdin (or a process with no stdin stream at all) is refused the
390
390
  same way, naming `--email`/`--password-stdin`; every refusal happens before any
391
391
  login request. `--status` cannot be combined with `--email` or `--password-stdin`.
392
- Even on an interactive terminal, `--password-stdin` suppresses terminal echo
393
- while the single line is read and restores it afterwards; a stdin stream that is
394
- closed or errors mid-read is refused cleanly (exit 2, never a traceback).
392
+ On supported POSIX terminals, `--password-stdin` suppresses terminal echo
393
+ while the single line is read and restores it afterwards. When suppression is
394
+ unavailable (including Windows consoles), or stdin's interactivity cannot be
395
+ determined, it warns on stderr before reading that the terminal may display
396
+ the password. Noninteractive pipes do not need suppression and stay quiet.
397
+ A stdin stream that is closed or errors mid-read is refused cleanly
398
+ (exit 2, never a traceback).
395
399
  AMS commands may omit both target flags while this session is present, except
396
400
  that a `prod` session still needs `--environment prod` on every command. Explicit
397
401
  flags and target files must match it exactly. A session within 60 seconds of
@@ -432,8 +436,9 @@ printf '%s\n' "$ADMIN_PASSWORD" | \
432
436
  - `--tenant-id` is validated locally (lowercase a-z only, e.g. `acmeclinic`)
433
437
  before any network call; anything else is refused without a request.
434
438
  - The admin password comes only from a hidden interactive prompt or
435
- `--password-stdin` (exactly one stdin line, echo-suppressed). There is no
436
- `--password` flag, and the password is never echoed or logged.
439
+ `--password-stdin` (exactly one stdin line, with terminal echo handling as
440
+ described above). There is no `--password` flag, and the CLI never prints or
441
+ logs the password.
437
442
  - Output: a `tenants.register` envelope with the tenant ID, status, tier,
438
443
  admin ID and `email_otp_sent`, plus a next-step hint pointing at
439
444
  `hc tenants verify-email`. A 409 is reported as "A tenant with this ID
@@ -351,7 +351,7 @@ for `login`/`--status`, and `{"schema_version": 1, "ok": true, "removed":
351
351
  true|false, "server_session_revoked": false}` for `logout`.
352
352
 
353
353
  For CI and agents, log in non-interactively: pass `--email` and pipe the password
354
- to `--password-stdin` (read as exactly one stdin line, never echoed, never a
354
+ to `--password-stdin` (read as exactly one stdin line, never printed by the CLI, never a
355
355
  flag value — there is no `--password` option):
356
356
 
357
357
  ```bash
@@ -371,9 +371,13 @@ prompt (no `GetPassWarning`, no echoed password); a missing email on a
371
371
  non-interactive stdin (or a process with no stdin stream at all) is refused the
372
372
  same way, naming `--email`/`--password-stdin`; every refusal happens before any
373
373
  login request. `--status` cannot be combined with `--email` or `--password-stdin`.
374
- Even on an interactive terminal, `--password-stdin` suppresses terminal echo
375
- while the single line is read and restores it afterwards; a stdin stream that is
376
- closed or errors mid-read is refused cleanly (exit 2, never a traceback).
374
+ On supported POSIX terminals, `--password-stdin` suppresses terminal echo
375
+ while the single line is read and restores it afterwards. When suppression is
376
+ unavailable (including Windows consoles), or stdin's interactivity cannot be
377
+ determined, it warns on stderr before reading that the terminal may display
378
+ the password. Noninteractive pipes do not need suppression and stay quiet.
379
+ A stdin stream that is closed or errors mid-read is refused cleanly
380
+ (exit 2, never a traceback).
377
381
  AMS commands may omit both target flags while this session is present, except
378
382
  that a `prod` session still needs `--environment prod` on every command. Explicit
379
383
  flags and target files must match it exactly. A session within 60 seconds of
@@ -414,8 +418,9 @@ printf '%s\n' "$ADMIN_PASSWORD" | \
414
418
  - `--tenant-id` is validated locally (lowercase a-z only, e.g. `acmeclinic`)
415
419
  before any network call; anything else is refused without a request.
416
420
  - The admin password comes only from a hidden interactive prompt or
417
- `--password-stdin` (exactly one stdin line, echo-suppressed). There is no
418
- `--password` flag, and the password is never echoed or logged.
421
+ `--password-stdin` (exactly one stdin line, with terminal echo handling as
422
+ described above). There is no `--password` flag, and the CLI never prints or
423
+ logs the password.
419
424
  - Output: a `tenants.register` envelope with the tenant ID, status, tier,
420
425
  admin ID and `email_otp_sent`, plus a next-step hint pointing at
421
426
  `hc tenants verify-email`. A 409 is reported as "A tenant with this ID
@@ -116,7 +116,7 @@ def create_download_command(dependencies: AmsDependencies) -> click.Command:
116
116
  def execute():
117
117
  target = resolve_tenant_target(environment, tenant_id)
118
118
  target_data.update(environment=target.environment, tenant_id=target.tenant_id)
119
- preflight_agent_files(invocation, target, methods=("download",))
119
+ preflight_agent_files(invocation, target, methods=("stream_download",))
120
120
  # The output path is reserved before sign-in inside the operation, so a
121
121
  # bad path never reaches the network (and never overwrites anything).
122
122
  return download_agent_file(dependencies, target, agent_id, file_id, output_file)
@@ -250,24 +250,29 @@ def download_agent_file(
250
250
 
251
251
  agent_id = _identifier(agent_id, "agent ID")
252
252
  file_id = _identifier(file_id, "file ID")
253
+ digest = hashlib.sha256()
254
+ size_bytes = 0
253
255
  with private_binary_output(output) as write, dependencies.authenticated_sdk_factory(target) as sdk:
254
- resource = _resource(sdk, ("download",))
256
+ resource = _resource(sdk, ("stream_download",))
255
257
  try:
256
- content = resource.download(agent_id, file_id)
258
+ with resource.stream_download(agent_id, file_id) as chunks:
259
+ for chunk in chunks:
260
+ write(chunk)
261
+ digest.update(chunk)
262
+ size_bytes += len(chunk)
257
263
  except HealthCloudHTTPError as error:
258
264
  refusal = _not_found(error, "file", file_id, agent_id)
259
265
  if refusal is not None:
260
266
  raise refusal from error
261
267
  raise
262
- write(content)
263
268
  return succeeded(
264
269
  "agent-files.download",
265
270
  _target(target, agent_id, file_id),
266
271
  {
267
272
  "download": {
268
273
  "path": str(output),
269
- "size_bytes": len(content),
270
- "sha256": hashlib.sha256(content).hexdigest(),
274
+ "size_bytes": size_bytes,
275
+ "sha256": digest.hexdigest(),
271
276
  }
272
277
  },
273
278
  read_only=True,
@@ -39,9 +39,8 @@ class _StdinEchoSuppression:
39
39
 
40
40
  On POSIX terminals the tty line discipline echoes every character a peer
41
41
  writes, which would print the password while ``readline`` waits. Terminal
42
- support is probed defensively: on non-tty streams, closed descriptors or
43
- platforms without ``termios`` the guard does nothing and the read proceeds
44
- as before.
42
+ support is probed defensively. Non-tty streams need no suppression; if
43
+ suppression fails on a potentially interactive stream, warn before reading.
45
44
  """
46
45
 
47
46
  def __init__(self, stream: Any) -> None:
@@ -50,21 +49,27 @@ class _StdinEchoSuppression:
50
49
  self._fd: int | None = None
51
50
  self._original: Any = None
52
51
  try:
52
+ if not stream.isatty():
53
+ return
54
+ fd = stream.fileno()
55
+ if not os.isatty(fd):
56
+ return
57
+
53
58
  import termios
54
59
 
55
- fd = stream.fileno()
56
- if stream.isatty() and os.isatty(fd):
57
- original = termios.tcgetattr(fd)
58
- attrs = list(original)
59
- attrs[3] = attrs[3] & ~termios.ECHO
60
- termios.tcsetattr(fd, termios.TCSANOW, attrs)
61
- self._fd = fd
62
- self._original = original
60
+ original = termios.tcgetattr(fd)
61
+ attrs = list(original)
62
+ attrs[3] = attrs[3] & ~termios.ECHO
63
+ termios.tcsetattr(fd, termios.TCSANOW, attrs)
64
+ self._fd = fd
65
+ self._original = original
63
66
  except Exception:
64
- # Best-effort: no tty, no termios, a closed stream or a dead peer
65
- # (termios.error is not an OSError) must never break the read.
66
- self._fd = None
67
- self._original = None
67
+ # Unknown interactivity or unavailable terminal control must not
68
+ # silently leave a user typing a visible password.
69
+ click.echo(
70
+ "Warning: --password-stdin could not disable terminal echo; the terminal may display your password.",
71
+ err=True,
72
+ )
68
73
 
69
74
  def restore(self) -> None:
70
75
  if self._fd is None or self._original is None:
@@ -79,7 +84,7 @@ class _StdinEchoSuppression:
79
84
 
80
85
 
81
86
  def _read_password_from_stdin(stream: Any) -> str:
82
- """Read exactly one line from ``stream`` for ``--password-stdin``; never echo it."""
87
+ """Read one stdin line, suppressing terminal echo when supported or warning."""
83
88
 
84
89
  if stream is None:
85
90
  raise click.UsageError("--password-stdin requires a stdin input stream; none is attached to this process.")
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "healthcloud-cli"
7
- version = "3.10.2"
7
+ version = "3.10.4"
8
8
  description = "Command-line interface for the HealthCloud MCP gateway, generated from the shared MCP tool manifest."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.14"