bt-cli 0.4.71__tar.gz → 0.4.73__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 (254) hide show
  1. {bt_cli-0.4.71 → bt_cli-0.4.73}/CLAUDE.md +3 -2
  2. {bt_cli-0.4.71 → bt_cli-0.4.73}/PKG-INFO +1 -1
  3. {bt_cli-0.4.71 → bt_cli-0.4.73}/pyproject.toml +1 -1
  4. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/__init__.py +1 -1
  5. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/cli.py +100 -350
  6. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/commands/learn.py +1 -1
  7. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/commands/quick.py +31 -31
  8. bt_cli-0.4.73/src/bt_cli/core/command_tree.py +82 -0
  9. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/core/output.py +3 -1
  10. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/core/prompts.py +5 -5
  11. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/bundles.py +1 -1
  12. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/permissions.py +1 -1
  13. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/requests.py +2 -2
  14. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/resources.py +2 -2
  15. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epml/commands/rbp_cmdgrps.py +1 -1
  16. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epml/commands/rbp_hostgrps.py +1 -1
  17. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epml/commands/rbp_tmdategrps.py +1 -1
  18. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epml/commands/rbp_usergrps.py +1 -1
  19. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epmw/commands/policies.py +3 -3
  20. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epmw/commands/quick.py +4 -4
  21. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pra/commands/group_policies.py +1 -1
  22. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pra/commands/jump_clients.py +1 -1
  23. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pra/commands/jump_items.py +4 -4
  24. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pra/commands/quick.py +16 -16
  25. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pra/commands/users.py +2 -2
  26. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pra/commands/vault.py +3 -3
  27. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/commands/accounts.py +3 -3
  28. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/commands/assets.py +1 -1
  29. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/commands/attributes.py +2 -2
  30. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/commands/clouds.py +2 -2
  31. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/commands/databases.py +1 -1
  32. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/commands/functional.py +4 -4
  33. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/commands/quick.py +65 -65
  34. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/commands/search.py +2 -2
  35. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/commands/secrets.py +10 -10
  36. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/commands/sessions.py +3 -3
  37. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/commands/systems.py +4 -4
  38. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/commands/workgroups.py +1 -1
  39. bt_cli-0.4.73/tests/core/test_command_tree.py +111 -0
  40. bt_cli-0.4.73/tests/core/test_json_stdout_purity.py +304 -0
  41. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/pws/test_commands.py +24 -13
  42. {bt_cli-0.4.71 → bt_cli-0.4.73}/.claude/skills/bt/SKILL.md +0 -0
  43. {bt_cli-0.4.71 → bt_cli-0.4.73}/.claude/skills/entitle/SKILL.md +0 -0
  44. {bt_cli-0.4.71 → bt_cli-0.4.73}/.claude/skills/epml/SKILL.md +0 -0
  45. {bt_cli-0.4.71 → bt_cli-0.4.73}/.claude/skills/epmw/SKILL.md +0 -0
  46. {bt_cli-0.4.71 → bt_cli-0.4.73}/.claude/skills/pra/SKILL.md +0 -0
  47. {bt_cli-0.4.71 → bt_cli-0.4.73}/.claude/skills/pws/SKILL.md +0 -0
  48. {bt_cli-0.4.71 → bt_cli-0.4.73}/.env.example +0 -0
  49. {bt_cli-0.4.71 → bt_cli-0.4.73}/.github/workflows/ci.yml +0 -0
  50. {bt_cli-0.4.71 → bt_cli-0.4.73}/.github/workflows/release.yml +0 -0
  51. {bt_cli-0.4.71 → bt_cli-0.4.73}/.gitignore +0 -0
  52. {bt_cli-0.4.71 → bt_cli-0.4.73}/README.md +0 -0
  53. {bt_cli-0.4.71 → bt_cli-0.4.73}/assets/cli-help.png +0 -0
  54. {bt_cli-0.4.71 → bt_cli-0.4.73}/assets/cli-output.png +0 -0
  55. {bt_cli-0.4.71 → bt_cli-0.4.73}/bt-cli-cheatsheet.html +0 -0
  56. {bt_cli-0.4.71 → bt_cli-0.4.73}/bt-cli.spec +0 -0
  57. {bt_cli-0.4.71 → bt_cli-0.4.73}/bt_entry.py +0 -0
  58. {bt_cli-0.4.71 → bt_cli-0.4.73}/epml-clients-server-side-filters-plan.md +0 -0
  59. {bt_cli-0.4.71 → bt_cli-0.4.73}/epml-implementation-plan.md +0 -0
  60. {bt_cli-0.4.71 → bt_cli-0.4.73}/pf-implementation-plan.md +0 -0
  61. {bt_cli-0.4.71 → bt_cli-0.4.73}/scripts/bt_entry.py +0 -0
  62. {bt_cli-0.4.71 → bt_cli-0.4.73}/scripts/pf_onboard.py +0 -0
  63. {bt_cli-0.4.71 → bt_cli-0.4.73}/scripts/sync-package-data.sh +0 -0
  64. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/commands/__init__.py +0 -0
  65. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/commands/configure.py +0 -0
  66. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/core/__init__.py +0 -0
  67. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/core/auth.py +0 -0
  68. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/core/client.py +0 -0
  69. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/core/config.py +0 -0
  70. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/core/config_file.py +0 -0
  71. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/core/csv_utils.py +0 -0
  72. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/core/errors.py +0 -0
  73. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/core/rest_debug.py +0 -0
  74. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/data/CLAUDE.md +0 -0
  75. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/data/__init__.py +0 -0
  76. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/data/skills/bt/SKILL.md +0 -0
  77. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/data/skills/entitle/SKILL.md +0 -0
  78. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/data/skills/epml/SKILL.md +0 -0
  79. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/data/skills/epmw/SKILL.md +0 -0
  80. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/data/skills/pf/SKILL.md +0 -0
  81. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/data/skills/pra/SKILL.md +0 -0
  82. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/data/skills/pws/SKILL.md +0 -0
  83. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/data/skills/secrets/SKILL.md +0 -0
  84. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/data/skills/session-analysis/SKILL.md +0 -0
  85. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/__init__.py +0 -0
  86. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/client/__init__.py +0 -0
  87. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/client/base.py +0 -0
  88. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/__init__.py +0 -0
  89. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/accounts.py +0 -0
  90. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/applications.py +0 -0
  91. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/audit.py +0 -0
  92. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/auth.py +0 -0
  93. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/integrations.py +0 -0
  94. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/jit.py +0 -0
  95. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/policies.py +0 -0
  96. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/roles.py +0 -0
  97. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/users.py +0 -0
  98. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/workflows.py +0 -0
  99. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/models/__init__.py +0 -0
  100. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/models/bundle.py +0 -0
  101. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/models/common.py +0 -0
  102. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/models/integration.py +0 -0
  103. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/models/permission.py +0 -0
  104. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/models/policy.py +0 -0
  105. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/models/resource.py +0 -0
  106. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/models/role.py +0 -0
  107. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/models/user.py +0 -0
  108. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/entitle/models/workflow.py +0 -0
  109. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epml/__init__.py +0 -0
  110. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epml/client/__init__.py +0 -0
  111. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epml/client/base.py +0 -0
  112. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epml/commands/__init__.py +0 -0
  113. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epml/commands/audit.py +0 -0
  114. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epml/commands/auth.py +0 -0
  115. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epml/commands/client_pkg.py +0 -0
  116. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epml/commands/clients.py +0 -0
  117. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epml/commands/external_apis.py +0 -0
  118. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epml/commands/hosts.py +0 -0
  119. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epml/commands/iolog.py +0 -0
  120. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epml/commands/license.py +0 -0
  121. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epml/commands/quick.py +0 -0
  122. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epml/commands/rbp_entitlement.py +0 -0
  123. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epml/commands/rbp_policy.py +0 -0
  124. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epml/commands/rbp_roles.py +0 -0
  125. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epml/commands/rbp_tests.py +0 -0
  126. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epml/commands/rbp_tx.py +0 -0
  127. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epml/commands/settings.py +0 -0
  128. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epml/commands/siems.py +0 -0
  129. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epml/commands/users.py +0 -0
  130. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epml/models/__init__.py +0 -0
  131. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epmw/__init__.py +0 -0
  132. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epmw/client/__init__.py +0 -0
  133. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epmw/client/base.py +0 -0
  134. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epmw/commands/__init__.py +0 -0
  135. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epmw/commands/audits.py +0 -0
  136. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epmw/commands/auth.py +0 -0
  137. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epmw/commands/computers.py +0 -0
  138. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epmw/commands/events.py +0 -0
  139. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epmw/commands/groups.py +0 -0
  140. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epmw/commands/requests.py +0 -0
  141. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epmw/commands/roles.py +0 -0
  142. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epmw/commands/tasks.py +0 -0
  143. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epmw/commands/users.py +0 -0
  144. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/epmw/models/__init__.py +0 -0
  145. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pf/__init__.py +0 -0
  146. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pf/client/__init__.py +0 -0
  147. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pf/client/base.py +0 -0
  148. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pf/commands/__init__.py +0 -0
  149. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pf/commands/auth.py +0 -0
  150. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pf/commands/machines.py +0 -0
  151. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pf/commands/tokens.py +0 -0
  152. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pf/commands/user.py +0 -0
  153. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pf/commands/users.py +0 -0
  154. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pra/__init__.py +0 -0
  155. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pra/client/__init__.py +0 -0
  156. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pra/client/base.py +0 -0
  157. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pra/commands/__init__.py +0 -0
  158. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pra/commands/auth.py +0 -0
  159. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pra/commands/import_export.py +0 -0
  160. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pra/commands/jump_groups.py +0 -0
  161. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pra/commands/jumpoints.py +0 -0
  162. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pra/commands/policies.py +0 -0
  163. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pra/commands/teams.py +0 -0
  164. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pra/models/__init__.py +0 -0
  165. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pra/models/common.py +0 -0
  166. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pra/models/group_policy.py +0 -0
  167. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pra/models/jump_client.py +0 -0
  168. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pra/models/jump_group.py +0 -0
  169. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pra/models/jump_item.py +0 -0
  170. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pra/models/jumpoint.py +0 -0
  171. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pra/models/team.py +0 -0
  172. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pra/models/user.py +0 -0
  173. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pra/models/vault.py +0 -0
  174. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/__init__.py +0 -0
  175. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/client/__init__.py +0 -0
  176. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/client/base.py +0 -0
  177. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/client/beyondinsight.py +0 -0
  178. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/client/passwordsafe.py +0 -0
  179. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/commands/__init__.py +0 -0
  180. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/commands/audit.py +0 -0
  181. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/commands/auth.py +0 -0
  182. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/commands/config.py +0 -0
  183. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/commands/credentials.py +0 -0
  184. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/commands/directories.py +0 -0
  185. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/commands/import_export.py +0 -0
  186. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/commands/platforms.py +0 -0
  187. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/commands/users.py +0 -0
  188. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/config.py +0 -0
  189. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/models/__init__.py +0 -0
  190. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/models/account.py +0 -0
  191. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/models/asset.py +0 -0
  192. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/models/common.py +0 -0
  193. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/pws/models/system.py +0 -0
  194. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/secrets/__init__.py +0 -0
  195. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/secrets/client/__init__.py +0 -0
  196. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/secrets/client/base.py +0 -0
  197. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/secrets/commands/__init__.py +0 -0
  198. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/secrets/commands/_hints.py +0 -0
  199. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/secrets/commands/auth.py +0 -0
  200. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/secrets/commands/dynamic.py +0 -0
  201. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/secrets/commands/folders.py +0 -0
  202. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/secrets/commands/integrations.py +0 -0
  203. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/secrets/commands/leases.py +0 -0
  204. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/secrets/commands/static.py +0 -0
  205. {bt_cli-0.4.71 → bt_cli-0.4.73}/src/bt_cli/secrets/models/__init__.py +0 -0
  206. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/__init__.py +0 -0
  207. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/conftest.py +0 -0
  208. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/core/__init__.py +0 -0
  209. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/core/test_auth.py +0 -0
  210. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/core/test_config.py +0 -0
  211. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/core/test_config_file.py +0 -0
  212. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/core/test_errors.py +0 -0
  213. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/core/test_output.py +0 -0
  214. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/core/test_rest_debug.py +0 -0
  215. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/entitle/__init__.py +0 -0
  216. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/entitle/test_client.py +0 -0
  217. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/entitle/test_commands.py +0 -0
  218. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/entitle-smoke-test.sh +0 -0
  219. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/epml/__init__.py +0 -0
  220. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/epml/test_client.py +0 -0
  221. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/epml/test_commands.py +0 -0
  222. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/epmw/__init__.py +0 -0
  223. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/epmw/test_client.py +0 -0
  224. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/epmw/test_commands.py +0 -0
  225. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/epmw-quick-test-plan.md +0 -0
  226. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/fixtures/__init__.py +0 -0
  227. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/fixtures/responses.py +0 -0
  228. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/integration/__init__.py +0 -0
  229. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/integration/conftest.py +0 -0
  230. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/integration/helpers.py +0 -0
  231. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/integration/test_entitle_integration.py +0 -0
  232. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/integration/test_epmw_integration.py +0 -0
  233. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/integration/test_epmw_lifecycle.py +0 -0
  234. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/integration/test_pra_integration.py +0 -0
  235. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/integration/test_pra_lifecycle.py +0 -0
  236. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/integration/test_pws_integration.py +0 -0
  237. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/integration/test_pws_lifecycle.py +0 -0
  238. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/pf/__init__.py +0 -0
  239. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/pf/test_client.py +0 -0
  240. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/pf/test_commands.py +0 -0
  241. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/pra/__init__.py +0 -0
  242. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/pra/test_client.py +0 -0
  243. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/pra/test_commands.py +0 -0
  244. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/pra/test_jump_item_fixes.py +0 -0
  245. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/pra-smoke-test.sh +0 -0
  246. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/pra-test-plan.md +0 -0
  247. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/pws/__init__.py +0 -0
  248. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/pws/test_client.py +0 -0
  249. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/pws/test_quick_sessions.py +0 -0
  250. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/pws-quick-test-plan.md +0 -0
  251. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/pws-smoke-test.sh +0 -0
  252. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/secrets/__init__.py +0 -0
  253. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/secrets/test_client.py +0 -0
  254. {bt_cli-0.4.71 → bt_cli-0.4.73}/tests/secrets/test_commands.py +0 -0
@@ -1,6 +1,6 @@
1
1
  # BT-CLI
2
2
 
3
- BeyondTrust Platform CLI for Password Safe, Entitle, PRA, EPM Windows, EPM Linux, and the BeyondTrust Secrets API. **Version: 0.4.71**
3
+ BeyondTrust Platform CLI for Password Safe, Entitle, PRA, EPM Windows, EPM Linux, and the BeyondTrust Secrets API. **Version: 0.4.73**
4
4
 
5
5
  ## Setup
6
6
 
@@ -82,7 +82,8 @@ PASSWORD=$(bt pws quick checkout -s server -a admin --raw)
82
82
  - PRA K8s tunnels: Require Linux jumpoint
83
83
  - PWS assets: Must create via workgroup endpoint
84
84
  - ECM integration: PWS system name must match PRA jump item name
85
- - **PRA `-o json` is pure JSON on stdout** — all human status/error banners go to **stderr** (`core/output.py` `err_console`), so `... -o json | jq` is safe. API 4xx `errors` objects are surfaced field-by-field, not collapsed to "Validation Failed".
85
+ - **`-o json` is pure JSON on stdout — in every product.** All human status/progress banners *and interactive prompts* go to **stderr** (`core/output.py` `err_console`; `typer.confirm`/`typer.prompt` are called with `err=True`), so `... -o json | jq` and `json.load(stdin)` are safe even for `quick` workflow commands that narrate their steps. Enforced by static guards in `tests/core/test_json_stdout_purity.py` — when adding a command, use `print_success`/`print_warning`/`print_info` or `err_console.print` for anything that isn't the command's data. Consequence: piping *table* output to a file drops the narration (it's on stderr) — that's intended. PRA API 4xx `errors` objects are surfaced field-by-field, not collapsed to "Validation Failed".
86
+ - **`bt tree` / `bt find` are derived from the live Typer app** (`core/command_tree.py` walks the Click tree) — **never hardcode a command list**. They used to be hand-maintained literals and silently drifted to 278-of-460 commands missing (all of `bt pws sessions`/`audit`, the whole `bt pf` product) before 0.4.73. `tests/core/test_command_tree.py` fails if any registered command is undiscoverable. New commands need no tree/find edit; help text comes from the docstring's first line.
86
87
  - **PRA tunnel create gates fields by `tunnel_type`**: tcp→`--ports`, mssql→`--username`/`--database`, k8s→`--url`/`--ca-cert`. **psql/mysql are created BARE** — the public Config API has no write path for their username/database (POST rejects, PATCH no-ops, PUT 405s) though GET shows them; CLI warns + ignores those flags. Set in `/login` UI.
87
88
  - **PRA `export jump-items` defaults to a REAL export** (all types: shell/rdp/vnc/web/tunnel, full type-specific columns) that round-trips through `import jump-items`; `--sample` gives the blank template. `bt pra jump-items web create` exists.
88
89
  - **PRA vault `associate -t protocol_tunnel` is MSSQL-only** (live-verified): server rejects psql/mysql/tcp/k8s with "Only SQL Server Tunnels are allowed" — use tag/criteria association for those. **TCP `--ports` needs listen;destination *pairs*** (even count; odd → 400 "number of parameters is invalid"). Jumpoint listing is `bt pra jumpoints list` (plural).
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: bt-cli
3
- Version: 0.4.71
3
+ Version: 0.4.73
4
4
  Summary: BeyondTrust Platform CLI (unofficial) - Password Safe, Entitle, PRA, EPM
5
5
  Author-email: Dave Grendysz <dgrendysz@beyondtrust.com>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "bt-cli"
7
- version = "0.4.71"
7
+ version = "0.4.73"
8
8
  description = "BeyondTrust Platform CLI (unofficial) - Password Safe, Entitle, PRA, EPM"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -1,3 +1,3 @@
1
1
  """BeyondTrust Unified Admin CLI."""
2
2
 
3
- __version__ = "0.4.71"
3
+ __version__ = "0.4.73"
@@ -263,9 +263,10 @@ def find_command(
263
263
  bt find secret # Find secret-related commands
264
264
  bt find jump # Find jump-related commands
265
265
  """
266
+ from rich.markup import escape
266
267
  from rich.table import Table
267
268
 
268
- # Build command registry
269
+ # Built from the live command tree, so it can never drift from reality
269
270
  commands = _get_all_commands()
270
271
 
271
272
  # Search
@@ -276,7 +277,7 @@ def find_command(
276
277
  matches.append((cmd_path, cmd_help))
277
278
 
278
279
  if not matches:
279
- console.print(f"[yellow]No commands found matching '{term}'[/yellow]")
280
+ console.print(f"[yellow]No commands found matching '{escape(term)}'[/yellow]")
280
281
  console.print("\nTry: bt tree # Show all commands")
281
282
  return
282
283
 
@@ -286,374 +287,123 @@ def find_command(
286
287
 
287
288
  for cmd_path, cmd_help in sorted(matches):
288
289
  # Truncate help text
289
- short_help = cmd_help[:60] + "..." if len(cmd_help) > 60 else cmd_help
290
- table.add_row(cmd_path, short_help)
290
+ short = cmd_help[:60] + "..." if len(cmd_help) > 60 else cmd_help
291
+ table.add_row(escape(cmd_path), escape(short))
291
292
 
292
293
  console.print(table)
293
294
  console.print(f"\n[dim]{len(matches)} command(s) found[/dim]")
294
295
 
295
296
 
297
+ def _chunk_verbs(names: list[str], width: int = 58) -> list[str]:
298
+ """Pack subcommand names into pipe-joined lines of at most `width` chars."""
299
+ rows: list[str] = []
300
+ current = ""
301
+ for name in names:
302
+ candidate = f"{current}|{name}" if current else name
303
+ if current and len(candidate) > width:
304
+ rows.append(current)
305
+ current = name
306
+ else:
307
+ current = candidate
308
+ if current:
309
+ rows.append(current)
310
+ return rows
311
+
312
+
313
+ def _render_tree_node(node, group, full: bool, top_level: bool = False) -> None:
314
+ """Recursively add a Click group's children to a Rich tree node.
315
+
316
+ Groups whose children are all leaves collapse onto a single line
317
+ ("accounts list|get|create|delete") to keep the full tree readable;
318
+ --full expands every command onto its own line with its help text.
319
+ """
320
+ from rich.markup import escape
321
+
322
+ from .core import command_tree as ct
323
+
324
+ for name, sub in ct.children(group):
325
+ style = "bold yellow" if top_level else "green"
326
+ label = f"[{style}]{escape(name)}[/{style}]"
327
+ help_text = ct.short_help(sub)
328
+
329
+ if not ct.is_group(sub):
330
+ if help_text:
331
+ label += f" - [dim]{escape(help_text)}[/dim]"
332
+ node.add(label)
333
+ continue
334
+
335
+ kids = ct.children(sub)
336
+ if kids and not ct.has_subgroups(sub) and not full and not top_level:
337
+ # Compact: collapse the group's verbs onto as few lines as possible.
338
+ # Chunked by hand because Rich would character-wrap "a|b|c" mid-word.
339
+ rows = _chunk_verbs([n for n, _ in kids])
340
+ if len(rows) == 1:
341
+ node.add(f"{label} {escape(rows[0])}")
342
+ else:
343
+ child = node.add(label)
344
+ for row in rows:
345
+ child.add(escape(row))
346
+ continue
347
+
348
+ if help_text:
349
+ label += f" - [dim]{escape(help_text)}[/dim]"
350
+ _render_tree_node(node.add(label), sub, full)
351
+
352
+
296
353
  @app.command("tree")
297
354
  def tree_command(
298
- product: Optional[str] = typer.Argument(None, help="Filter by product: pws, pra, entitle, epmw"),
355
+ path: Optional[list[str]] = typer.Argument(
356
+ None, help="Filter to a command path, e.g. 'pws' or 'pws sessions'"
357
+ ),
358
+ full: bool = typer.Option(
359
+ False, "--full", "-f", help="Expand every command on its own line with help text"
360
+ ),
299
361
  ) -> None:
300
362
  """Show command hierarchy tree.
301
363
 
302
- Displays the full command tree for navigation.
364
+ Built by introspecting the live command tree, so it always reflects
365
+ every registered command.
303
366
 
304
367
  Examples:
305
- bt tree # Show all commands
306
- bt tree pws # Show only PWS commands
307
- bt tree pra # Show only PRA commands
368
+ bt tree # Show all commands
369
+ bt tree pws # Show only PWS commands
370
+ bt tree pws sessions # Drill into a subcommand group
371
+ bt tree pws --full # One line per command, with help text
308
372
  """
373
+ from rich.markup import escape
309
374
  from rich.tree import Tree
310
375
 
311
- if product:
312
- product = product.lower()
313
- if product not in ["pws", "pra", "entitle", "epmw", "epml", "secrets", "pf", "quick", "configure"]:
314
- console.print(f"[red]Unknown product: {product}[/red]")
315
- console.print("Available: pws, pra, entitle, epmw, epml, secrets, pf, quick, configure")
316
- raise typer.Exit(1)
317
-
318
- tree = Tree("[bold cyan]bt[/bold cyan]")
319
-
320
- # Top-level commands
321
- if not product:
322
- tree.add("[green]version[/green] - Show version")
323
- tree.add("[green]whoami[/green] - Test all connections")
324
- tree.add("[green]find[/green] <term> - Search commands")
325
- tree.add("[green]tree[/green] - Show this tree")
326
- tree.add("[green]skills[/green] - Install Claude Code skills")
327
- tree.add("[green]configure[/green] - Configure products")
328
-
329
- # PWS
330
- if not product or product == "pws":
331
- pws = tree.add("[bold yellow]pws[/bold yellow] - Password Safe")
332
- pws.add("[green]auth[/green] test")
333
- pws.add("[green]search[/green] <query> - Search across all entities")
334
-
335
- systems = pws.add("[green]systems[/green] list|get|create|update|delete")
336
- accounts = pws.add("[green]accounts[/green] list|get|create|update|delete|rotate")
337
- pws.add("[green]functional[/green] list|get|create|update|delete")
338
- pws.add("[green]assets[/green] list|search|get|create|update|delete")
339
- pws.add("[green]credentials[/green] checkout|checkin")
340
- pws.add("[green]platforms[/green] list|get")
341
- pws.add("[green]workgroups[/green] list|get")
342
-
343
- secrets = pws.add("[green]secrets[/green]")
344
- secrets.add("safes list|get|create|delete")
345
- secrets.add("folders list|get|create|delete")
346
- secrets.add("secrets list|get|create|create-text|create-file|delete")
347
-
348
- pws.add("[green]quick[/green] checkout|onboard|offboard")
349
-
350
- # PRA
351
- if not product or product == "pra":
352
- pra = tree.add("[bold yellow]pra[/bold yellow] - Privileged Remote Access")
353
- pra.add("[green]auth[/green] test")
354
- pra.add("[green]jumpoint[/green] list|get")
355
- pra.add("[green]jump-groups[/green] list|get|create")
356
-
357
- ji = pra.add("[green]jump-items[/green]")
358
- ji.add("shell list|get|create|update|delete")
359
- ji.add("rdp list|get|create|delete")
360
-
361
- vault = pra.add("[green]vault[/green]")
362
- vault.add("accounts list|get|create|delete|checkout|checkin|get-user-data|get-public-key")
363
- vault.add("groups list|get")
364
-
365
- pra.add("[green]users[/green] list|get|update|delete|group-policies|provision")
366
- pra.add("[green]teams[/green] list|get")
367
- pol = pra.add("[green]policies[/green]")
368
- pol.add("jump list|get")
369
- pol.add("session list")
370
- pol.add("group list|get|create|update|delete|copy|provision")
371
- pol.add(" + jumpoints|members|jump-groups|vault-accounts|")
372
- pol.add(" vault-account-groups|teams (list|add|remove)")
373
-
374
- pra.add("[green]quick[/green] shell-jump|rdp-jump|change-group-policy-update")
375
-
376
- # Entitle
377
- if not product or product == "entitle":
378
- ent = tree.add("[bold yellow]entitle[/bold yellow] - Just-in-Time Access")
379
- ent.add("[green]auth[/green] test")
380
- ent.add("[green]integrations[/green] list|get")
381
- ent.add("[green]resources[/green] list|get|create-virtual|delete")
382
- ent.add("[green]roles[/green] list|get")
383
- ent.add("[green]bundles[/green] list|get|create|delete")
384
- ent.add("[green]workflows[/green] list|get")
385
- ent.add("[green]users[/green] list|get")
386
- ent.add("[green]permissions[/green] list|revoke")
387
- ent.add("[green]policies[/green] list|get")
388
- ent.add("[green]accounts[/green] list")
389
- ent.add("[green]agents[/green] list|get|status")
390
-
391
- # EPMW
392
- if not product or product == "epmw":
393
- epmw = tree.add("[bold yellow]epmw[/bold yellow] - EPM Windows")
394
- epmw.add("[green]auth[/green] test")
395
- epmw.add("[green]computers[/green] list|get|archive")
396
- epmw.add("[green]groups[/green] list|get")
397
- epmw.add("[green]policies[/green] list|get")
398
- epmw.add("[green]requests[/green] list|get|approve|deny")
399
- epmw.add("[green]quick[/green] approve-all")
400
-
401
- # EPML
402
- if not product or product == "epml":
403
- epml = tree.add("[bold yellow]epml[/bold yellow] - EPM Linux")
404
- epml.add("[green]auth[/green] test|status")
405
- epml.add("[green]settings[/green] list|get")
406
- epml.add("[green]users[/green] list|get")
407
- epml.add("[green]hosts[/green] list|features")
408
- epml.add("[green]license[/green] get")
409
- epml.add("[green]siems[/green] list")
410
- audit = epml.add("[green]audit[/green]")
411
- audit.add("sessions list|categories")
412
- epml.add("[green]client-pkg[/green] list|status|link")
413
- epml.add("[green]external-apis[/green] list|get")
414
- epml.add("[green]iolog[/green] list")
415
- rbp = epml.add("[green]rbp[/green] - Role-Based Policy")
416
- rbp.add("cmdgrps list|create|delete + commands list|add|clear|replace")
417
- rbp.add("hostgrps list|create|delete + hosts list|add|clear|replace")
418
- rbp.add("usergrps list|create|create-multiple|delete + users list|add|clear|replace")
419
- rbp.add("tmdategrps list|create|delete + tmdates list|add|clear|replace")
420
- rbp.add("roles list|create|delete|duplicate")
421
- rbp.add(" + cmdgrps|hostgrps|usergrps|tmdategrps list|add|remove")
422
- rbp.add("entitlement run [--raw]")
423
- rbp.add("policy export|import|revert|versions|diff|snapshot|delete-all")
424
- rbp.add("tests suites list|get|create|update|delete")
425
- rbp.add(" + tests add|update|delete + run --suite <id>")
426
- rbp.add("tx status|begin|commit|rollback|abort")
427
- epml.add("[green]quick[/green] tests-then-deploy")
428
-
429
- # Secrets API
430
- if not product or product == "secrets":
431
- secrets = tree.add("[bold yellow]secrets[/bold yellow] - BeyondTrust Secrets API")
432
- secrets.add("[green]auth[/green] test|status")
433
- secrets.add("[green]folders[/green] list|get|create|delete")
434
- secrets.add("[green]static[/green] list|get|create|update|delete")
435
- secrets.add("[green]dynamic[/green] list|get|generate|create|delete")
436
- secrets.add("[green]leases[/green] list|get|revoke")
437
- secrets.add("[green]integrations[/green] list|get|create|update|delete")
438
-
439
- # Quick
440
- if not product or product == "quick":
441
- quick = tree.add("[bold yellow]quick[/bold yellow] - Cross-product workflows")
442
- quick.add("[green]pasm-onboard[/green] - Onboard to PWS + PRA")
443
- quick.add("[green]pasm-offboard[/green] - Remove from PWS + PRA")
444
- quick.add("[green]pasm-search[/green] - Search across PWS + PRA")
376
+ from .core import command_tree as ct
377
+
378
+ root = ct.get_root_command()
379
+ parts = [p.lower() for p in (path or [])]
380
+
381
+ node_cmd = ct.resolve(root, parts)
382
+ if node_cmd is None:
383
+ console.print(f"[red]Unknown command path: {escape(' '.join(parts))}[/red]")
384
+ available = ", ".join(n for n, _ in ct.children(root))
385
+ console.print(f"Available: {escape(available)}")
386
+ raise typer.Exit(1)
387
+
388
+ label = "[bold cyan]" + " ".join(["bt"] + parts) + "[/bold cyan]"
389
+ if not ct.is_group(node_cmd):
390
+ help_text = ct.short_help(node_cmd)
391
+ console.print(f"{label}" + (f" - [dim]{escape(help_text)}[/dim]" if help_text else ""))
392
+ return
445
393
 
394
+ tree = Tree(label)
395
+ _render_tree_node(tree, node_cmd, full, top_level=not parts)
446
396
  console.print(tree)
447
397
 
398
+ total = sum(1 for _ in ct.walk(node_cmd))
399
+ console.print(f"\n[dim]{total} command(s)[/dim]")
400
+
448
401
 
449
402
  def _get_all_commands() -> list[tuple[str, str]]:
450
- """Build list of all commands with their help text."""
451
- commands = [
452
- ("bt version", "Show version information"),
453
- ("bt whoami", "Test all configured products and show connection info"),
454
- ("bt find <term>", "Search for commands by name or description"),
455
- ("bt tree", "Show command hierarchy tree"),
456
- ("bt skills", "Install Claude Code skills"),
457
- ("bt configure", "Configure bt-cli settings"),
458
- # PWS
459
- ("bt pws auth test", "Test Password Safe connection"),
460
- ("bt pws search <query>", "Search across all PWS entities"),
461
- ("bt pws systems list", "List managed systems"),
462
- ("bt pws systems get", "Get a managed system"),
463
- ("bt pws systems create", "Create a managed system"),
464
- ("bt pws systems update", "Update a managed system"),
465
- ("bt pws systems delete", "Delete a managed system"),
466
- ("bt pws accounts list", "List managed accounts"),
467
- ("bt pws accounts get", "Get a managed account"),
468
- ("bt pws accounts create", "Create a managed account"),
469
- ("bt pws accounts update", "Update a managed account"),
470
- ("bt pws accounts delete", "Delete a managed account"),
471
- ("bt pws accounts rotate", "Rotate account password"),
472
- ("bt pws functional list", "List functional accounts (for auto-management)"),
473
- ("bt pws functional get", "Get a functional account"),
474
- ("bt pws functional create", "Create a functional account"),
475
- ("bt pws functional update", "Update a functional account"),
476
- ("bt pws functional delete", "Delete a functional account"),
477
- ("bt pws assets list", "List assets"),
478
- ("bt pws assets search", "Search assets"),
479
- ("bt pws assets get", "Get an asset"),
480
- ("bt pws assets create", "Create an asset"),
481
- ("bt pws assets update", "Update an asset"),
482
- ("bt pws assets delete", "Delete an asset"),
483
- ("bt pws credentials checkout", "Check out account credentials"),
484
- ("bt pws credentials checkin", "Check in account credentials"),
485
- ("bt pws secrets safes list", "List Secrets Safe safes"),
486
- ("bt pws secrets folders list", "List Secrets Safe folders"),
487
- ("bt pws secrets secrets list", "List secrets"),
488
- ("bt pws secrets secrets create", "Create a secret"),
489
- ("bt pws secrets secrets create-text", "Create a text secret (supports --file)"),
490
- ("bt pws secrets secrets create-file", "Create a file secret"),
491
- ("bt pws quick checkout", "Quick checkout workflow"),
492
- ("bt pws quick onboard", "Quick onboard system + account"),
493
- ("bt pws quick offboard", "Quick offboard system"),
494
- # PRA
495
- ("bt pra auth test", "Test PRA connection"),
496
- ("bt pra jumpoint list", "List jumpoints"),
497
- ("bt pra jump-groups list", "List jump groups"),
498
- ("bt pra jump-groups create", "Create a jump group"),
499
- ("bt pra jump-items shell list", "List shell jump items"),
500
- ("bt pra jump-items shell create", "Create a shell jump item"),
501
- ("bt pra jump-items shell update", "Update a shell jump item"),
502
- ("bt pra jump-items shell delete", "Delete a shell jump item"),
503
- ("bt pra jump-items rdp list", "List RDP jump items"),
504
- ("bt pra jump-items rdp create", "Create an RDP jump item"),
505
- ("bt pra vault accounts list", "List vault accounts"),
506
- ("bt pra vault accounts get", "Get a vault account"),
507
- ("bt pra vault accounts create", "Create a vault account"),
508
- ("bt pra vault accounts checkout", "Checkout vault credentials"),
509
- ("bt pra vault accounts get-user-data", "Generate EC2 user-data for SSH CA"),
510
- ("bt pra vault accounts get-public-key", "Get SSH CA public key"),
511
- ("bt pra users list", "List PRA users"),
512
- ("bt pra users update", "Update a user (--unlock to clear failed_logins)"),
513
- ("bt pra users group-policies", "Show GPs a user is a member of"),
514
- ("bt pra users provision -u <id>", "Recompute permissions for a user"),
515
- ("bt pra policies group list", "List Group Policies"),
516
- ("bt pra policies group create --name X", "Create a Group Policy"),
517
- ("bt pra policies group copy <id> --name Y", "Duplicate a Group Policy"),
518
- ("bt pra policies group members list <id>", "List members of a GP"),
519
- ("bt pra policies group jump-groups add <id>", "Attach a Jump Group to a GP"),
520
- ("bt pra policies group vault-accounts add <id>", "Attach a Vault Account to a GP"),
521
- ("bt pra policies group teams add <id>", "Attach a Team to a GP"),
522
- ("bt pra quick change-group-policy-update", "Interactive: toggle a user's GP memberships"),
523
- # Entitle
524
- ("bt entitle auth test", "Test Entitle connection"),
525
- ("bt entitle integrations list", "List integrations"),
526
- ("bt entitle resources list", "List resources"),
527
- ("bt entitle resources create-virtual", "Create a virtual resource"),
528
- ("bt entitle roles list", "List roles"),
529
- ("bt entitle bundles list", "List bundles"),
530
- ("bt entitle workflows list", "List workflows"),
531
- ("bt entitle users list", "List users"),
532
- ("bt entitle permissions list", "List permissions"),
533
- ("bt entitle permissions revoke", "Revoke a permission"),
534
- ("bt entitle agents list", "List agents"),
535
- ("bt entitle agents status", "Show agent status summary"),
536
- # EPMW
537
- ("bt epmw auth test", "Test EPM Windows connection"),
538
- ("bt epmw computers list", "List managed computers"),
539
- ("bt epmw computers archive", "Archive a computer"),
540
- ("bt epmw groups list", "List computer groups"),
541
- ("bt epmw policies list", "List policies"),
542
- ("bt epmw requests list", "List elevation requests"),
543
- ("bt epmw requests approve", "Approve an elevation request"),
544
- ("bt epmw requests deny", "Deny an elevation request"),
545
- ("bt epmw quick approve-all", "Approve all pending requests"),
546
- # EPML
547
- ("bt epml auth test", "Test EPM Linux connection"),
548
- ("bt epml auth status", "Show EPM Linux configuration status"),
549
- ("bt epml settings list", "List site-level settings"),
550
- ("bt epml settings get", "Get a single setting by key"),
551
- ("bt epml users list", "List EPM Linux users"),
552
- ("bt epml users get", "Get a user by ID"),
553
- ("bt epml hosts list", "List PMUL hosts"),
554
- ("bt epml hosts features", "Show feature flags per PMUL host"),
555
- ("bt epml license get", "Get the EPM Linux license"),
556
- ("bt epml siems list", "List SIEM forwarders"),
557
- ("bt epml audit sessions list", "List audit session records"),
558
- ("bt epml audit sessions categories", "List audit session categories"),
559
- ("bt epml client-pkg list", "List built client installer packages"),
560
- ("bt epml client-pkg status", "Client package build status"),
561
- ("bt epml client-pkg link", "Get presigned download URL for a package"),
562
- ("bt epml external-apis list", "List external API integrations"),
563
- ("bt epml external-apis get", "Get an external API by ID"),
564
- ("bt epml iolog list", "List iolog files for a host"),
565
- # EPML RBP
566
- ("bt epml rbp cmdgrps list", "List RBP command groups"),
567
- ("bt epml rbp cmdgrps create", "Create an RBP command group"),
568
- ("bt epml rbp cmdgrps delete", "Delete RBP command groups"),
569
- ("bt epml rbp cmdgrps commands list", "List commands within a cmdgrp"),
570
- ("bt epml rbp cmdgrps commands add", "Add commands to a cmdgrp"),
571
- ("bt epml rbp cmdgrps commands clear", "Clear ALL commands in a cmdgrp"),
572
- ("bt epml rbp cmdgrps commands replace", "Replace cmdgrp's full command list"),
573
- ("bt epml rbp hostgrps list", "List RBP host groups"),
574
- ("bt epml rbp hostgrps create", "Create an RBP host group"),
575
- ("bt epml rbp hostgrps delete", "Delete RBP host groups"),
576
- ("bt epml rbp hostgrps hosts list", "List hosts within a hostgrp"),
577
- ("bt epml rbp hostgrps hosts add", "Add hosts to a hostgrp"),
578
- ("bt epml rbp hostgrps hosts clear", "Clear ALL hosts in a hostgrp"),
579
- ("bt epml rbp hostgrps hosts replace", "Replace hostgrp's full host list"),
580
- ("bt epml rbp usergrps list", "List RBP user groups"),
581
- ("bt epml rbp usergrps create", "Create an RBP user group"),
582
- ("bt epml rbp usergrps create-multiple", "Bulk-create user groups from a JSON file"),
583
- ("bt epml rbp usergrps delete", "Delete RBP user groups"),
584
- ("bt epml rbp usergrps users list", "List users within a usergrp"),
585
- ("bt epml rbp usergrps users add", "Add users to a usergrp"),
586
- ("bt epml rbp usergrps users clear", "Clear ALL users in a usergrp"),
587
- ("bt epml rbp usergrps users replace", "Replace usergrp's full user list"),
588
- ("bt epml rbp tmdategrps list", "List RBP time/date groups"),
589
- ("bt epml rbp tmdategrps create", "Create an RBP time/date group"),
590
- ("bt epml rbp tmdategrps delete", "Delete RBP time/date groups"),
591
- ("bt epml rbp tmdategrps tmdates list", "List time/date entries in a group"),
592
- ("bt epml rbp tmdategrps tmdates add", "Add time/date entries"),
593
- ("bt epml rbp tmdategrps tmdates clear", "Clear ALL time/dates in a group"),
594
- ("bt epml rbp tmdategrps tmdates replace", "Replace the group's full tmdate list"),
595
- ("bt epml rbp roles list", "List RBP roles"),
596
- ("bt epml rbp roles create", "Create an RBP role"),
597
- ("bt epml rbp roles delete", "Delete RBP roles"),
598
- ("bt epml rbp roles duplicate", "Duplicate an RBP role"),
599
- ("bt epml rbp roles cmdgrps list/add/remove", "Manage cmdgrps on a role"),
600
- ("bt epml rbp roles hostgrps list/add/remove", "Manage hostgrps on a role"),
601
- ("bt epml rbp roles usergrps list/add/remove", "Manage usergrps on a role"),
602
- ("bt epml rbp roles tmdategrps list/add/remove", "Manage tmdategrps on a role"),
603
- ("bt epml rbp entitlement run", "Run the entitlement report"),
604
- ("bt epml rbp policy export", "Export the full RBP DB"),
605
- ("bt epml rbp policy import", "Import an RBP DB serialization"),
606
- ("bt epml rbp policy revert", "Revert policy to last committed state"),
607
- ("bt epml rbp policy versions", "List RBP policy versions"),
608
- ("bt epml rbp policy diff", "Diff current draft against a prior version"),
609
- ("bt epml rbp policy snapshot", "Get full current RBP snapshot"),
610
- ("bt epml rbp policy delete-all", "Delete the entire RBP DB (destructive)"),
611
- ("bt epml rbp tx status", "Show RBP transaction state"),
612
- ("bt epml rbp tx begin", "Begin an RBP transaction"),
613
- ("bt epml rbp tx commit", "Commit the RBP transaction"),
614
- ("bt epml rbp tx rollback", "Rollback the RBP transaction"),
615
- ("bt epml rbp tx abort", "Abort the RBP transaction"),
616
- ("bt epml rbp tests suites list", "List RBP test suites"),
617
- ("bt epml rbp tests suites get", "Get a test suite (with tests)"),
618
- ("bt epml rbp tests suites create", "Create a test suite"),
619
- ("bt epml rbp tests suites update", "Update a test suite"),
620
- ("bt epml rbp tests suites delete", "Delete a test suite"),
621
- ("bt epml rbp tests tests add", "Add a test to a suite"),
622
- ("bt epml rbp tests tests update", "Update a test"),
623
- ("bt epml rbp tests tests delete", "Delete a test"),
624
- ("bt epml rbp tests run", "Run a test suite, exit non-zero on failure"),
625
- ("bt epml quick tests-then-deploy", "Run tests, commit or rollback the open RBP transaction"),
626
- # Secrets API
627
- ("bt secrets auth test", "Test BeyondTrust Secrets API connection"),
628
- ("bt secrets auth status", "Show Secrets API configuration status"),
629
- ("bt secrets folders list", "List folders (server-side filter)"),
630
- ("bt secrets folders get", "Get folder metadata"),
631
- ("bt secrets folders create", "Create a folder"),
632
- ("bt secrets folders delete", "Delete a folder"),
633
- ("bt secrets static list", "List static secrets"),
634
- ("bt secrets static get", "Get a static secret value"),
635
- ("bt secrets static create", "Create a static secret"),
636
- ("bt secrets static update", "Update a static secret (bumps version)"),
637
- ("bt secrets static delete", "Delete a static secret"),
638
- ("bt secrets dynamic list", "List dynamic-secret configs"),
639
- ("bt secrets dynamic get", "Get a dynamic-secret config"),
640
- ("bt secrets dynamic generate", "Mint a fresh dynamic credential (e.g. AWS STS)"),
641
- ("bt secrets dynamic create", "Create a dynamic-secret config"),
642
- ("bt secrets dynamic delete", "Delete a dynamic-secret config"),
643
- ("bt secrets leases list", "List active leases for a dynamic secret"),
644
- ("bt secrets leases get", "Get lease details by id"),
645
- ("bt secrets leases revoke", "Revoke a lease (scope-gated; lab returns 403)"),
646
- ("bt secrets integrations list", "List integrations"),
647
- ("bt secrets integrations get", "Get an integration"),
648
- ("bt secrets integrations create", "Create an integration"),
649
- ("bt secrets integrations update", "Update an integration (PUT or --partial PATCH)"),
650
- ("bt secrets integrations delete", "Delete an integration"),
651
- # Quick
652
- ("bt quick pasm-onboard", "Onboard host to PWS + PRA (Total PASM)"),
653
- ("bt quick pasm-offboard", "Offboard host from PWS + PRA"),
654
- ("bt quick pasm-search", "Search across PWS + PRA"),
655
- ]
656
- return commands
403
+ """List every command with its help text, read from the live command tree."""
404
+ from .core import command_tree as ct
405
+
406
+ return list(ct.walk(ct.get_root_command()))
657
407
 
658
408
 
659
409
  @app.command("skills")
@@ -221,7 +221,7 @@ def clear_learnings(
221
221
  bt learn clear --force
222
222
  """
223
223
  if not force:
224
- if not typer.confirm("Clear all learnings?"):
224
+ if not typer.confirm("Clear all learnings?", err=True):
225
225
  console.print("[yellow]Cancelled[/yellow]")
226
226
  raise typer.Exit(0)
227
227