wxcli 1.2.0__py3-none-any.whl

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 (413) hide show
  1. wxcli/__init__.py +4 -0
  2. wxcli/_playbook/.claude/agents/migration-advisor.md +239 -0
  3. wxcli/_playbook/.claude/agents/wxc-calling-builder.md +946 -0
  4. wxcli/_playbook/.claude/rules/cleanup.md +29 -0
  5. wxcli/_playbook/.claude/rules/cucm-migration.md +58 -0
  6. wxcli/_playbook/.claude/rules/org-health.md +14 -0
  7. wxcli/_playbook/.claude/settings.json +8 -0
  8. wxcli/_playbook/.claude/skills/audit-compliance/SKILL.md +515 -0
  9. wxcli/_playbook/.claude/skills/call-control/SKILL.md +747 -0
  10. wxcli/_playbook/.claude/skills/configure-features/SKILL.md +623 -0
  11. wxcli/_playbook/.claude/skills/configure-routing/SKILL.md +627 -0
  12. wxcli/_playbook/.claude/skills/contact-center/SKILL.md +1181 -0
  13. wxcli/_playbook/.claude/skills/cucm-migrate/SKILL.md +820 -0
  14. wxcli/_playbook/.claude/skills/customer-assist/SKILL.md +443 -0
  15. wxcli/_playbook/.claude/skills/device-platform/SKILL.md +407 -0
  16. wxcli/_playbook/.claude/skills/manage-call-settings/SKILL.md +757 -0
  17. wxcli/_playbook/.claude/skills/manage-devices/SKILL.md +790 -0
  18. wxcli/_playbook/.claude/skills/manage-identity/SKILL.md +638 -0
  19. wxcli/_playbook/.claude/skills/manage-licensing/SKILL.md +528 -0
  20. wxcli/_playbook/.claude/skills/manage-meetings/SKILL.md +708 -0
  21. wxcli/_playbook/.claude/skills/messaging-bots/SKILL.md +365 -0
  22. wxcli/_playbook/.claude/skills/messaging-spaces/SKILL.md +520 -0
  23. wxcli/_playbook/.claude/skills/org-health/SKILL.md +159 -0
  24. wxcli/_playbook/.claude/skills/provision-calling/SKILL.md +421 -0
  25. wxcli/_playbook/.claude/skills/query-live/SKILL.md +183 -0
  26. wxcli/_playbook/.claude/skills/query-live/domains/call-flow-trace.md +223 -0
  27. wxcli/_playbook/.claude/skills/query-live/domains/call-history.md +44 -0
  28. wxcli/_playbook/.claude/skills/query-live/domains/features.md +169 -0
  29. wxcli/_playbook/.claude/skills/query-live/domains/numbers.md +93 -0
  30. wxcli/_playbook/.claude/skills/query-live/domains/people-and-settings.md +146 -0
  31. wxcli/_playbook/.claude/skills/query-live/domains/routing.md +124 -0
  32. wxcli/_playbook/.claude/skills/reporting/SKILL.md +501 -0
  33. wxcli/_playbook/.claude/skills/reporting/references/cdr-recipes.md +1628 -0
  34. wxcli/_playbook/.claude/skills/reporting-cc/SKILL.md +251 -0
  35. wxcli/_playbook/.claude/skills/reporting-meetings/SKILL.md +290 -0
  36. wxcli/_playbook/.claude/skills/teardown/SKILL.md +214 -0
  37. wxcli/_playbook/.claude/skills/video-mesh/SKILL.md +379 -0
  38. wxcli/_playbook/.claude/skills/wxc-calling-debug/SKILL.md +475 -0
  39. wxcli/_playbook/CLAUDE.md +373 -0
  40. wxcli/_playbook/docs/reference/CLAUDE.md +25 -0
  41. wxcli/_playbook/docs/reference/admin-apps-data.md +643 -0
  42. wxcli/_playbook/docs/reference/admin-audit-security.md +322 -0
  43. wxcli/_playbook/docs/reference/admin-hybrid.md +383 -0
  44. wxcli/_playbook/docs/reference/admin-identity-scim.md +1007 -0
  45. wxcli/_playbook/docs/reference/admin-licensing.md +414 -0
  46. wxcli/_playbook/docs/reference/admin-org-management.md +586 -0
  47. wxcli/_playbook/docs/reference/admin-partner.md +357 -0
  48. wxcli/_playbook/docs/reference/archive/wxc-sdk-patterns.md +1229 -0
  49. wxcli/_playbook/docs/reference/archive/wxcadm-advanced.md +835 -0
  50. wxcli/_playbook/docs/reference/archive/wxcadm-core.md +743 -0
  51. wxcli/_playbook/docs/reference/archive/wxcadm-devices-workspaces.md +1305 -0
  52. wxcli/_playbook/docs/reference/archive/wxcadm-features.md +849 -0
  53. wxcli/_playbook/docs/reference/archive/wxcadm-locations.md +938 -0
  54. wxcli/_playbook/docs/reference/archive/wxcadm-person.md +1255 -0
  55. wxcli/_playbook/docs/reference/archive/wxcadm-routing.md +1262 -0
  56. wxcli/_playbook/docs/reference/authentication.md +965 -0
  57. wxcli/_playbook/docs/reference/call-control.md +1205 -0
  58. wxcli/_playbook/docs/reference/call-features-additional.md +2541 -0
  59. wxcli/_playbook/docs/reference/call-features-major.md +1320 -0
  60. wxcli/_playbook/docs/reference/call-routing.md +2304 -0
  61. wxcli/_playbook/docs/reference/contact-center-analytics.md +1049 -0
  62. wxcli/_playbook/docs/reference/contact-center-core.md +1614 -0
  63. wxcli/_playbook/docs/reference/contact-center-journey.md +457 -0
  64. wxcli/_playbook/docs/reference/contact-center-routing.md +1138 -0
  65. wxcli/_playbook/docs/reference/devices-core.md +1869 -0
  66. wxcli/_playbook/docs/reference/devices-dect.md +1150 -0
  67. wxcli/_playbook/docs/reference/devices-platform.md +467 -0
  68. wxcli/_playbook/docs/reference/devices-workspaces.md +1426 -0
  69. wxcli/_playbook/docs/reference/emergency-services.md +1122 -0
  70. wxcli/_playbook/docs/reference/location-calling-core.md +2037 -0
  71. wxcli/_playbook/docs/reference/location-calling-media.md +1334 -0
  72. wxcli/_playbook/docs/reference/location-recording-advanced.md +1482 -0
  73. wxcli/_playbook/docs/reference/meetings-content.md +473 -0
  74. wxcli/_playbook/docs/reference/meetings-core.md +903 -0
  75. wxcli/_playbook/docs/reference/meetings-infrastructure.md +899 -0
  76. wxcli/_playbook/docs/reference/meetings-settings.md +850 -0
  77. wxcli/_playbook/docs/reference/messaging-bots.md +1091 -0
  78. wxcli/_playbook/docs/reference/messaging-spaces.md +695 -0
  79. wxcli/_playbook/docs/reference/person-call-settings-behavior.md +1639 -0
  80. wxcli/_playbook/docs/reference/person-call-settings-handling.md +1394 -0
  81. wxcli/_playbook/docs/reference/person-call-settings-media.md +1898 -0
  82. wxcli/_playbook/docs/reference/person-call-settings-permissions.md +1329 -0
  83. wxcli/_playbook/docs/reference/provisioning.md +1366 -0
  84. wxcli/_playbook/docs/reference/reporting-analytics.md +1318 -0
  85. wxcli/_playbook/docs/reference/self-service-call-settings.md +1020 -0
  86. wxcli/_playbook/docs/reference/virtual-lines.md +1132 -0
  87. wxcli/_playbook/docs/reference/webhooks-events.md +1444 -0
  88. wxcli/_playbook/docs/reference/wxcadm-xsi-realtime.md +953 -0
  89. wxcli/_version.py +24 -0
  90. wxcli/auth.py +137 -0
  91. wxcli/commands/__init__.py +0 -0
  92. wxcli/commands/_registry.py +181 -0
  93. wxcli/commands/activation_email.py +103 -0
  94. wxcli/commands/admin_recordings.py +585 -0
  95. wxcli/commands/analytics.py +105 -0
  96. wxcli/commands/announcement_playlists.py +219 -0
  97. wxcli/commands/announcements.py +519 -0
  98. wxcli/commands/archive_users.py +36 -0
  99. wxcli/commands/attachment_actions.py +60 -0
  100. wxcli/commands/audit_events.py +83 -0
  101. wxcli/commands/authorizations.py +113 -0
  102. wxcli/commands/auto_attendant.py +642 -0
  103. wxcli/commands/broadworks_billing_reports.py +126 -0
  104. wxcli/commands/broadworks_enterprises.py +160 -0
  105. wxcli/commands/broadworks_subscribers.py +319 -0
  106. wxcli/commands/broadworks_workspaces.py +108 -0
  107. wxcli/commands/call_controls.py +1304 -0
  108. wxcli/commands/call_park.py +494 -0
  109. wxcli/commands/call_pickup.py +229 -0
  110. wxcli/commands/call_queue.py +1878 -0
  111. wxcli/commands/call_recording.py +707 -0
  112. wxcli/commands/call_routing.py +1610 -0
  113. wxcli/commands/call_settings_for_me_phase_5.py +212 -0
  114. wxcli/commands/caller_reputation.py +169 -0
  115. wxcli/commands/calling_service.py +305 -0
  116. wxcli/commands/cc_address_book.py +770 -0
  117. wxcli/commands/cc_agent_greetings.py +242 -0
  118. wxcli/commands/cc_agent_summaries.py +39 -0
  119. wxcli/commands/cc_agent_wellbeing.py +216 -0
  120. wxcli/commands/cc_agents.py +425 -0
  121. wxcli/commands/cc_ai_assistant.py +55 -0
  122. wxcli/commands/cc_ai_feature.py +294 -0
  123. wxcli/commands/cc_audio_files.py +149 -0
  124. wxcli/commands/cc_auto_csat.py +311 -0
  125. wxcli/commands/cc_aux_code.py +458 -0
  126. wxcli/commands/cc_business_hour.py +353 -0
  127. wxcli/commands/cc_call_monitoring.py +228 -0
  128. wxcli/commands/cc_callbacks.py +194 -0
  129. wxcli/commands/cc_campaign.py +212 -0
  130. wxcli/commands/cc_captures.py +39 -0
  131. wxcli/commands/cc_contact_list.py +169 -0
  132. wxcli/commands/cc_contact_number.py +295 -0
  133. wxcli/commands/cc_data_sources.py +235 -0
  134. wxcli/commands/cc_desktop_layout.py +380 -0
  135. wxcli/commands/cc_desktop_profile.py +322 -0
  136. wxcli/commands/cc_dial_number.py +511 -0
  137. wxcli/commands/cc_dial_plan.py +347 -0
  138. wxcli/commands/cc_dnc.py +101 -0
  139. wxcli/commands/cc_entry_point.py +545 -0
  140. wxcli/commands/cc_ewt.py +51 -0
  141. wxcli/commands/cc_flow.py +477 -0
  142. wxcli/commands/cc_global_vars.py +430 -0
  143. wxcli/commands/cc_holiday_list.py +335 -0
  144. wxcli/commands/cc_journey.py +1261 -0
  145. wxcli/commands/cc_legacy_flows.py +49 -0
  146. wxcli/commands/cc_multimedia_profile.py +436 -0
  147. wxcli/commands/cc_notification.py +51 -0
  148. wxcli/commands/cc_outdial_ani.py +604 -0
  149. wxcli/commands/cc_overrides.py +341 -0
  150. wxcli/commands/cc_queue.py +1083 -0
  151. wxcli/commands/cc_queue_stats.py +55 -0
  152. wxcli/commands/cc_realtime.py +51 -0
  153. wxcli/commands/cc_resource_collection.py +312 -0
  154. wxcli/commands/cc_search.py +46 -0
  155. wxcli/commands/cc_site.py +400 -0
  156. wxcli/commands/cc_skill.py +350 -0
  157. wxcli/commands/cc_skill_profile.py +289 -0
  158. wxcli/commands/cc_subscriptions.py +426 -0
  159. wxcli/commands/cc_summaries.py +130 -0
  160. wxcli/commands/cc_tasks.py +844 -0
  161. wxcli/commands/cc_team.py +325 -0
  162. wxcli/commands/cc_user_profiles.py +349 -0
  163. wxcli/commands/cc_users.py +701 -0
  164. wxcli/commands/cc_work_types.py +363 -0
  165. wxcli/commands/cdr.py +89 -0
  166. wxcli/commands/classifications.py +38 -0
  167. wxcli/commands/cleanup.py +1427 -0
  168. wxcli/commands/client_settings.py +72 -0
  169. wxcli/commands/conference.py +328 -0
  170. wxcli/commands/configure.py +72 -0
  171. wxcli/commands/converged_recordings.py +347 -0
  172. wxcli/commands/converged_recordings_export.py +310 -0
  173. wxcli/commands/cq_playlists.py +42 -0
  174. wxcli/commands/cucm.py +2794 -0
  175. wxcli/commands/cucm_config.py +129 -0
  176. wxcli/commands/customer_assist.py +373 -0
  177. wxcli/commands/data_sources.py +227 -0
  178. wxcli/commands/dect_devices.py +787 -0
  179. wxcli/commands/device_configurations.py +77 -0
  180. wxcli/commands/device_dynamic_settings.py +320 -0
  181. wxcli/commands/device_settings.py +1489 -0
  182. wxcli/commands/devices.py +280 -0
  183. wxcli/commands/domains.py +142 -0
  184. wxcli/commands/ecm.py +178 -0
  185. wxcli/commands/emergency_services.py +827 -0
  186. wxcli/commands/events.py +83 -0
  187. wxcli/commands/external_voicemail.py +52 -0
  188. wxcli/commands/groups.py +206 -0
  189. wxcli/commands/guest_management.py +76 -0
  190. wxcli/commands/hds.py +340 -0
  191. wxcli/commands/hot_desk.py +67 -0
  192. wxcli/commands/hot_desking_members.py +118 -0
  193. wxcli/commands/hot_desking_portal.py +124 -0
  194. wxcli/commands/hunt_group.py +577 -0
  195. wxcli/commands/hybrid_clusters.py +71 -0
  196. wxcli/commands/hybrid_connectors.py +67 -0
  197. wxcli/commands/identity_org.py +159 -0
  198. wxcli/commands/init_playbook.py +155 -0
  199. wxcli/commands/licenses.py +106 -0
  200. wxcli/commands/live_monitoring.py +40 -0
  201. wxcli/commands/location_call_handling.py +577 -0
  202. wxcli/commands/location_schedules.py +341 -0
  203. wxcli/commands/location_settings.py +1297 -0
  204. wxcli/commands/location_voicemail.py +494 -0
  205. wxcli/commands/locations.py +336 -0
  206. wxcli/commands/meeting_captions.py +110 -0
  207. wxcli/commands/meeting_chats.py +63 -0
  208. wxcli/commands/meeting_invitees.py +234 -0
  209. wxcli/commands/meeting_messages.py +28 -0
  210. wxcli/commands/meeting_participants.py +278 -0
  211. wxcli/commands/meeting_polls.py +111 -0
  212. wxcli/commands/meeting_preferences.py +515 -0
  213. wxcli/commands/meeting_qa.py +78 -0
  214. wxcli/commands/meeting_qualities.py +43 -0
  215. wxcli/commands/meeting_reports.py +101 -0
  216. wxcli/commands/meeting_session_types.py +105 -0
  217. wxcli/commands/meeting_site.py +57 -0
  218. wxcli/commands/meeting_slido.py +44 -0
  219. wxcli/commands/meeting_summaries.py +92 -0
  220. wxcli/commands/meeting_tracking_codes.py +233 -0
  221. wxcli/commands/meeting_transcripts.py +230 -0
  222. wxcli/commands/meetings.py +1997 -0
  223. wxcli/commands/memberships.py +164 -0
  224. wxcli/commands/messages.py +213 -0
  225. wxcli/commands/mode_management.py +244 -0
  226. wxcli/commands/my_call_settings.py +3577 -0
  227. wxcli/commands/numbers.py +405 -0
  228. wxcli/commands/operating_modes.py +410 -0
  229. wxcli/commands/org_contacts.py +284 -0
  230. wxcli/commands/org_health_cli.py +55 -0
  231. wxcli/commands/org_settings.py +71 -0
  232. wxcli/commands/organizations.py +83 -0
  233. wxcli/commands/paging_group.py +257 -0
  234. wxcli/commands/partner_admins.py +141 -0
  235. wxcli/commands/partner_reports.py +188 -0
  236. wxcli/commands/partner_tags.py +216 -0
  237. wxcli/commands/people.py +279 -0
  238. wxcli/commands/person_call_settings.py +71 -0
  239. wxcli/commands/pstn.py +280 -0
  240. wxcli/commands/recording_report.py +154 -0
  241. wxcli/commands/report_templates.py +38 -0
  242. wxcli/commands/reports.py +144 -0
  243. wxcli/commands/resource_group_memberships.py +160 -0
  244. wxcli/commands/resource_groups.py +67 -0
  245. wxcli/commands/roles.py +63 -0
  246. wxcli/commands/room_tabs.py +160 -0
  247. wxcli/commands/rooms.py +225 -0
  248. wxcli/commands/scim_bulk.py +46 -0
  249. wxcli/commands/scim_groups.py +246 -0
  250. wxcli/commands/scim_schemas.py +82 -0
  251. wxcli/commands/scim_users.py +283 -0
  252. wxcli/commands/security_audit.py +54 -0
  253. wxcli/commands/service_apps.py +51 -0
  254. wxcli/commands/single_number_reach.py +209 -0
  255. wxcli/commands/team_memberships.py +155 -0
  256. wxcli/commands/teams.py +153 -0
  257. wxcli/commands/ucm_profile.py +42 -0
  258. wxcli/commands/update.py +219 -0
  259. wxcli/commands/user_settings.py +5116 -0
  260. wxcli/commands/video_mesh.py +1090 -0
  261. wxcli/commands/virtual_extensions.py +502 -0
  262. wxcli/commands/virtual_line_settings.py +2072 -0
  263. wxcli/commands/webhooks.py +176 -0
  264. wxcli/commands/wholesale_billing_reports.py +147 -0
  265. wxcli/commands/wholesale_provisioning.py +523 -0
  266. wxcli/commands/workspace_locations.py +339 -0
  267. wxcli/commands/workspace_metrics.py +103 -0
  268. wxcli/commands/workspace_personalization.py +70 -0
  269. wxcli/commands/workspace_settings.py +3347 -0
  270. wxcli/commands/workspaces.py +279 -0
  271. wxcli/commands/xapi.py +114 -0
  272. wxcli/config.py +139 -0
  273. wxcli/errors.py +77 -0
  274. wxcli/main.py +210 -0
  275. wxcli/migration/CLAUDE.md +106 -0
  276. wxcli/migration/__init__.py +1 -0
  277. wxcli/migration/advisory/CLAUDE.md +196 -0
  278. wxcli/migration/advisory/__init__.py +46 -0
  279. wxcli/migration/advisory/advisor.py +107 -0
  280. wxcli/migration/advisory/advisory_patterns.py +2552 -0
  281. wxcli/migration/advisory/recommendation_rules.py +835 -0
  282. wxcli/migration/cucm/CLAUDE.md +74 -0
  283. wxcli/migration/cucm/__init__.py +5 -0
  284. wxcli/migration/cucm/connection.py +265 -0
  285. wxcli/migration/cucm/discovery.py +225 -0
  286. wxcli/migration/cucm/extractors/__init__.py +1 -0
  287. wxcli/migration/cucm/extractors/announcements.py +92 -0
  288. wxcli/migration/cucm/extractors/base.py +90 -0
  289. wxcli/migration/cucm/extractors/device_profiles.py +98 -0
  290. wxcli/migration/cucm/extractors/devices.py +193 -0
  291. wxcli/migration/cucm/extractors/e911.py +103 -0
  292. wxcli/migration/cucm/extractors/features.py +309 -0
  293. wxcli/migration/cucm/extractors/helpers.py +73 -0
  294. wxcli/migration/cucm/extractors/informational.py +295 -0
  295. wxcli/migration/cucm/extractors/locations.py +221 -0
  296. wxcli/migration/cucm/extractors/moh.py +100 -0
  297. wxcli/migration/cucm/extractors/remote_destinations.py +96 -0
  298. wxcli/migration/cucm/extractors/routing.py +493 -0
  299. wxcli/migration/cucm/extractors/shared_lines.py +146 -0
  300. wxcli/migration/cucm/extractors/templates.py +229 -0
  301. wxcli/migration/cucm/extractors/tier4.py +173 -0
  302. wxcli/migration/cucm/extractors/users.py +240 -0
  303. wxcli/migration/cucm/extractors/voicemail.py +243 -0
  304. wxcli/migration/cucm/extractors/workspaces.py +88 -0
  305. wxcli/migration/cucm/unity_connection.py +304 -0
  306. wxcli/migration/execute/CLAUDE.md +372 -0
  307. wxcli/migration/execute/__init__.py +303 -0
  308. wxcli/migration/execute/batch.py +277 -0
  309. wxcli/migration/execute/dependency.py +483 -0
  310. wxcli/migration/execute/engine.py +964 -0
  311. wxcli/migration/execute/handlers.py +2232 -0
  312. wxcli/migration/execute/planner.py +1939 -0
  313. wxcli/migration/execute/runtime.py +571 -0
  314. wxcli/migration/export/CLAUDE.md +49 -0
  315. wxcli/migration/export/__init__.py +8 -0
  316. wxcli/migration/export/csv_export.py +126 -0
  317. wxcli/migration/export/deployment_plan.py +479 -0
  318. wxcli/migration/export/json_export.py +60 -0
  319. wxcli/migration/models.py +941 -0
  320. wxcli/migration/phone_models.py +50 -0
  321. wxcli/migration/preflight/CLAUDE.md +52 -0
  322. wxcli/migration/preflight/__init__.py +89 -0
  323. wxcli/migration/preflight/checks.py +911 -0
  324. wxcli/migration/preflight/runner.py +293 -0
  325. wxcli/migration/rate_limiter.py +144 -0
  326. wxcli/migration/report/CLAUDE.md +245 -0
  327. wxcli/migration/report/__init__.py +7 -0
  328. wxcli/migration/report/appendix.py +2437 -0
  329. wxcli/migration/report/assembler.py +183 -0
  330. wxcli/migration/report/charts.py +263 -0
  331. wxcli/migration/report/executive.py +776 -0
  332. wxcli/migration/report/explainer.py +704 -0
  333. wxcli/migration/report/helpers.py +74 -0
  334. wxcli/migration/report/ingest.py +152 -0
  335. wxcli/migration/report/notice_templates.py +192 -0
  336. wxcli/migration/report/score.py +375 -0
  337. wxcli/migration/report/styles.py +1052 -0
  338. wxcli/migration/report/user_diff.py +1052 -0
  339. wxcli/migration/report/user_notice.py +425 -0
  340. wxcli/migration/state.py +139 -0
  341. wxcli/migration/store.py +860 -0
  342. wxcli/migration/transform/CLAUDE.md +107 -0
  343. wxcli/migration/transform/__init__.py +12 -0
  344. wxcli/migration/transform/analysis_pipeline.py +453 -0
  345. wxcli/migration/transform/analyzers/__init__.py +142 -0
  346. wxcli/migration/transform/analyzers/css_permission.py +189 -0
  347. wxcli/migration/transform/analyzers/css_routing.py +335 -0
  348. wxcli/migration/transform/analyzers/device_compatibility.py +122 -0
  349. wxcli/migration/transform/analyzers/dn_ambiguity.py +131 -0
  350. wxcli/migration/transform/analyzers/duplicate_user.py +221 -0
  351. wxcli/migration/transform/analyzers/extension_conflict.py +173 -0
  352. wxcli/migration/transform/analyzers/feature_approximation.py +227 -0
  353. wxcli/migration/transform/analyzers/layout_overflow.py +174 -0
  354. wxcli/migration/transform/analyzers/location_ambiguity.py +184 -0
  355. wxcli/migration/transform/analyzers/missing_data.py +300 -0
  356. wxcli/migration/transform/analyzers/selective_call_handling.py +394 -0
  357. wxcli/migration/transform/analyzers/shared_line.py +170 -0
  358. wxcli/migration/transform/analyzers/voicemail_compatibility.py +267 -0
  359. wxcli/migration/transform/analyzers/workspace_license.py +212 -0
  360. wxcli/migration/transform/cross_reference.py +1136 -0
  361. wxcli/migration/transform/cucm_pattern.py +246 -0
  362. wxcli/migration/transform/decisions.py +301 -0
  363. wxcli/migration/transform/e164.py +145 -0
  364. wxcli/migration/transform/engine.py +256 -0
  365. wxcli/migration/transform/mappers/CLAUDE.md +123 -0
  366. wxcli/migration/transform/mappers/__init__.py +76 -0
  367. wxcli/migration/transform/mappers/announcement_mapper.py +122 -0
  368. wxcli/migration/transform/mappers/base.py +190 -0
  369. wxcli/migration/transform/mappers/button_template_mapper.py +186 -0
  370. wxcli/migration/transform/mappers/call_forwarding_mapper.py +228 -0
  371. wxcli/migration/transform/mappers/call_settings_mapper.py +144 -0
  372. wxcli/migration/transform/mappers/css_mapper.py +868 -0
  373. wxcli/migration/transform/mappers/dect_mapper.py +367 -0
  374. wxcli/migration/transform/mappers/device_layout_mapper.py +289 -0
  375. wxcli/migration/transform/mappers/device_mapper.py +227 -0
  376. wxcli/migration/transform/mappers/device_profile_mapper.py +190 -0
  377. wxcli/migration/transform/mappers/device_settings_mapper.py +464 -0
  378. wxcli/migration/transform/mappers/e911_mapper.py +129 -0
  379. wxcli/migration/transform/mappers/ecbn_mapper.py +263 -0
  380. wxcli/migration/transform/mappers/executive_assistant_mapper.py +156 -0
  381. wxcli/migration/transform/mappers/feature_mapper.py +1179 -0
  382. wxcli/migration/transform/mappers/line_mapper.py +310 -0
  383. wxcli/migration/transform/mappers/location_mapper.py +235 -0
  384. wxcli/migration/transform/mappers/moh_mapper.py +114 -0
  385. wxcli/migration/transform/mappers/monitoring_mapper.py +221 -0
  386. wxcli/migration/transform/mappers/receptionist_mapper.py +245 -0
  387. wxcli/migration/transform/mappers/routing_mapper.py +821 -0
  388. wxcli/migration/transform/mappers/snr_mapper.py +201 -0
  389. wxcli/migration/transform/mappers/softkey_mapper.py +205 -0
  390. wxcli/migration/transform/mappers/user_mapper.py +264 -0
  391. wxcli/migration/transform/mappers/voicemail_group_mapper.py +286 -0
  392. wxcli/migration/transform/mappers/voicemail_mapper.py +514 -0
  393. wxcli/migration/transform/mappers/workspace_mapper.py +464 -0
  394. wxcli/migration/transform/normalizers.py +2008 -0
  395. wxcli/migration/transform/pattern_converter.py +106 -0
  396. wxcli/migration/transform/pipeline.py +271 -0
  397. wxcli/migration/transform/rules.py +255 -0
  398. wxcli/org_health/CLAUDE.md +63 -0
  399. wxcli/org_health/__init__.py +7 -0
  400. wxcli/org_health/analyze.py +93 -0
  401. wxcli/org_health/checks.py +458 -0
  402. wxcli/org_health/collector.py +62 -0
  403. wxcli/org_health/models.py +78 -0
  404. wxcli/org_health/report.py +300 -0
  405. wxcli/output.py +101 -0
  406. wxcli-1.2.0.dist-info/METADATA +505 -0
  407. wxcli-1.2.0.dist-info/RECORD +413 -0
  408. wxcli-1.2.0.dist-info/WHEEL +5 -0
  409. wxcli-1.2.0.dist-info/entry_points.txt +2 -0
  410. wxcli-1.2.0.dist-info/licenses/LICENSE +191 -0
  411. wxcli-1.2.0.dist-info/scm_file_list.json +751 -0
  412. wxcli-1.2.0.dist-info/scm_version.json +8 -0
  413. wxcli-1.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1090 @@
1
+ import json
2
+ import typer
3
+ from wxcli.auth import get_api
4
+ from wxcli.errors import WebexError, handle_rest_error
5
+ from wxcli.output import print_table, print_json
6
+ from wxcli.config import get_org_id
7
+
8
+
9
+ app = typer.Typer(help="Manage Webex Calling video-mesh.")
10
+
11
+
12
+ @app.command("list")
13
+ def cmd_list(
14
+ from_param: str = typer.Option(..., "--from", help="The starting date and time of the requested data in any [ISO"),
15
+ to: str = typer.Option(..., "--to", help="The ending date and time of the requested data in any [ISO 8"),
16
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
17
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
18
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
19
+ debug: bool = typer.Option(False, "--debug"),
20
+ ):
21
+ """List Clusters Availability."""
22
+ api = get_api(debug=debug)
23
+ url = f"https://webexapis.com/v1/videoMesh/clusters/availability"
24
+ params = {}
25
+ if from_param is not None:
26
+ params["from"] = from_param
27
+ if to is not None:
28
+ params["to"] = to
29
+ if limit > 0:
30
+ params["max"] = limit
31
+ if offset > 0:
32
+ params["start"] = offset
33
+ org_id = get_org_id()
34
+ if org_id is not None:
35
+ params["orgId"] = org_id
36
+ result = None
37
+ try:
38
+ result = api.session.rest_get(url, params=params)
39
+ except WebexError as e:
40
+ handle_rest_error(e)
41
+ result = result or []
42
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
43
+ if output == "json":
44
+ print_json(items)
45
+ else:
46
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name')], limit=limit)
47
+
48
+
49
+
50
+ @app.command("show")
51
+ def show(
52
+ cluster_id: str = typer.Argument(help="clusterId"),
53
+ from_param: str = typer.Option(..., "--from", help="The starting date and time of the requested data in any [ISO"),
54
+ to: str = typer.Option(..., "--to", help="The ending date and time of the requested data in any [ISO 8"),
55
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
56
+ debug: bool = typer.Option(False, "--debug"),
57
+ ):
58
+ """Get Cluster Availability."""
59
+ api = get_api(debug=debug)
60
+ url = f"https://webexapis.com/v1/videoMesh/clusters/availability/{cluster_id}"
61
+ params = {}
62
+ if from_param is not None:
63
+ params["from"] = from_param
64
+ if to is not None:
65
+ params["to"] = to
66
+ try:
67
+ result = api.session.rest_get(url, params=params)
68
+ except WebexError as e:
69
+ handle_rest_error(e)
70
+ if output == "json":
71
+ print_json(result)
72
+ else:
73
+ if isinstance(result, dict):
74
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
75
+ elif isinstance(result, list):
76
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
77
+ else:
78
+ print_json(result)
79
+
80
+
81
+
82
+ @app.command("list-availability")
83
+ def list_availability(
84
+ from_param: str = typer.Option(..., "--from", help="The starting date and time of the requested data in any [ISO"),
85
+ to: str = typer.Option(..., "--to", help="The ending date and time of the requested data in any [ISO 8"),
86
+ cluster_id: str = typer.Option(..., "--cluster-id", help="The unique Video Mesh cluster ID."),
87
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
88
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
89
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
90
+ debug: bool = typer.Option(False, "--debug"),
91
+ ):
92
+ """List Node Availability."""
93
+ api = get_api(debug=debug)
94
+ url = f"https://webexapis.com/v1/videoMesh/nodes/availability"
95
+ params = {}
96
+ if from_param is not None:
97
+ params["from"] = from_param
98
+ if to is not None:
99
+ params["to"] = to
100
+ if cluster_id is not None:
101
+ params["clusterId"] = cluster_id
102
+ if limit > 0:
103
+ params["max"] = limit
104
+ if offset > 0:
105
+ params["start"] = offset
106
+ result = None
107
+ try:
108
+ result = api.session.rest_get(url, params=params)
109
+ except WebexError as e:
110
+ handle_rest_error(e)
111
+ result = result or []
112
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
113
+ if output == "json":
114
+ print_json(items)
115
+ else:
116
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name')], limit=limit)
117
+
118
+
119
+
120
+ @app.command("show-availability")
121
+ def show_availability(
122
+ node_id: str = typer.Argument(help="nodeId"),
123
+ from_param: str = typer.Option(..., "--from", help="The starting date and time of the requested data in any [ISO"),
124
+ to: str = typer.Option(..., "--to", help="The ending date and time of the requested data in any [ISO 8"),
125
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
126
+ debug: bool = typer.Option(False, "--debug"),
127
+ ):
128
+ """Get Node Availability."""
129
+ api = get_api(debug=debug)
130
+ url = f"https://webexapis.com/v1/videoMesh/nodes/availability/{node_id}"
131
+ params = {}
132
+ if from_param is not None:
133
+ params["from"] = from_param
134
+ if to is not None:
135
+ params["to"] = to
136
+ try:
137
+ result = api.session.rest_get(url, params=params)
138
+ except WebexError as e:
139
+ handle_rest_error(e)
140
+ if output == "json":
141
+ print_json(result)
142
+ else:
143
+ if isinstance(result, dict):
144
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
145
+ elif isinstance(result, list):
146
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
147
+ else:
148
+ print_json(result)
149
+
150
+
151
+
152
+ @app.command("list-media-health-monitor-test")
153
+ def list_media_health_monitor_test(
154
+ trigger_type: str = typer.Option(..., "--trigger-type", help="Choices: OnDemand, Periodic, All"),
155
+ from_param: str = typer.Option(..., "--from", help="The start date and time of the requested data in any [ISO 86"),
156
+ to: str = typer.Option(..., "--to", help="The end date and time of the requested data in any [ISO 8601"),
157
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
158
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
159
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
160
+ debug: bool = typer.Option(False, "--debug"),
161
+ ):
162
+ """List Media Health Monitoring Tool Test results V2."""
163
+ api = get_api(debug=debug)
164
+ url = f"https://webexapis.com/v1/videoMesh/testResults/mediaHealthMonitorTest"
165
+ params = {}
166
+ if trigger_type is not None:
167
+ params["triggerType"] = trigger_type
168
+ if from_param is not None:
169
+ params["from"] = from_param
170
+ if to is not None:
171
+ params["to"] = to
172
+ if limit > 0:
173
+ params["max"] = limit
174
+ if offset > 0:
175
+ params["start"] = offset
176
+ org_id = get_org_id()
177
+ if org_id is not None:
178
+ params["orgId"] = org_id
179
+ result = None
180
+ try:
181
+ result = api.session.rest_get(url, params=params)
182
+ except WebexError as e:
183
+ handle_rest_error(e)
184
+ result = result or []
185
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
186
+ if output == "json":
187
+ print_json(items)
188
+ else:
189
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name')], limit=limit)
190
+
191
+
192
+
193
+ @app.command("list-clusters-media-health-monitor-test")
194
+ def list_clusters_media_health_monitor_test(
195
+ cluster_id: str = typer.Option(..., "--cluster-id", help="Unique ID of the Video Mesh cluster."),
196
+ trigger_type: str = typer.Option(..., "--trigger-type", help="Choices: OnDemand, Periodic, All"),
197
+ from_param: str = typer.Option(..., "--from", help="The start date and time of the requested data in any [ISO 86"),
198
+ to: str = typer.Option(..., "--to", help="The end date and time of the requested data in any [ISO 8601"),
199
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
200
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
201
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
202
+ debug: bool = typer.Option(False, "--debug"),
203
+ ):
204
+ """Get Media Health Monitoring Tool Test results for clusters V2."""
205
+ api = get_api(debug=debug)
206
+ url = f"https://webexapis.com/v1/videoMesh/testResults/mediaHealthMonitorTest/clusters"
207
+ params = {}
208
+ if cluster_id is not None:
209
+ params["clusterId"] = cluster_id
210
+ if trigger_type is not None:
211
+ params["triggerType"] = trigger_type
212
+ if from_param is not None:
213
+ params["from"] = from_param
214
+ if to is not None:
215
+ params["to"] = to
216
+ if limit > 0:
217
+ params["max"] = limit
218
+ if offset > 0:
219
+ params["start"] = offset
220
+ result = None
221
+ try:
222
+ result = api.session.rest_get(url, params=params)
223
+ except WebexError as e:
224
+ handle_rest_error(e)
225
+ result = result or []
226
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
227
+ if output == "json":
228
+ print_json(items)
229
+ else:
230
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name')], limit=limit)
231
+
232
+
233
+
234
+ @app.command("list-nodes-media-health-monitor-test")
235
+ def list_nodes_media_health_monitor_test(
236
+ node_id: str = typer.Option(..., "--node-id", help="Unique ID of the Video Mesh node."),
237
+ trigger_type: str = typer.Option(..., "--trigger-type", help="Choices: OnDemand, Periodic, All"),
238
+ from_param: str = typer.Option(..., "--from", help="The start date and time of the requested data in any [ISO 86"),
239
+ to: str = typer.Option(..., "--to", help="The end date and time of the requested data in any [ISO 8601"),
240
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
241
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
242
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
243
+ debug: bool = typer.Option(False, "--debug"),
244
+ ):
245
+ """Get Media Health Monitoring Tool Test results for node V2."""
246
+ api = get_api(debug=debug)
247
+ url = f"https://webexapis.com/v1/videoMesh/testResults/mediaHealthMonitorTest/nodes"
248
+ params = {}
249
+ if node_id is not None:
250
+ params["nodeId"] = node_id
251
+ if trigger_type is not None:
252
+ params["triggerType"] = trigger_type
253
+ if from_param is not None:
254
+ params["from"] = from_param
255
+ if to is not None:
256
+ params["to"] = to
257
+ if limit > 0:
258
+ params["max"] = limit
259
+ if offset > 0:
260
+ params["start"] = offset
261
+ result = None
262
+ try:
263
+ result = api.session.rest_get(url, params=params)
264
+ except WebexError as e:
265
+ handle_rest_error(e)
266
+ result = result or []
267
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
268
+ if output == "json":
269
+ print_json(items)
270
+ else:
271
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name')], limit=limit)
272
+
273
+
274
+
275
+ @app.command("list-cloud-overflow")
276
+ def list_cloud_overflow(
277
+ from_param: str = typer.Option(..., "--from", help="The starting date and time of the requested data in any [ISO"),
278
+ to: str = typer.Option(..., "--to", help="The ending date and time of the requested data in any [ISO 8"),
279
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
280
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
281
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
282
+ debug: bool = typer.Option(False, "--debug"),
283
+ ):
284
+ """List Overflow to Cloud details."""
285
+ api = get_api(debug=debug)
286
+ url = f"https://webexapis.com/v1/videoMesh/cloudOverflow"
287
+ params = {}
288
+ if from_param is not None:
289
+ params["from"] = from_param
290
+ if to is not None:
291
+ params["to"] = to
292
+ if limit > 0:
293
+ params["max"] = limit
294
+ if offset > 0:
295
+ params["start"] = offset
296
+ org_id = get_org_id()
297
+ if org_id is not None:
298
+ params["orgId"] = org_id
299
+ result = None
300
+ try:
301
+ result = api.session.rest_get(url, params=params)
302
+ except WebexError as e:
303
+ handle_rest_error(e)
304
+ result = result or []
305
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
306
+ if output == "json":
307
+ print_json(items)
308
+ else:
309
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name')], limit=limit)
310
+
311
+
312
+
313
+ @app.command("list-call-redirects-video-mesh")
314
+ def list_call_redirects_video_mesh(
315
+ from_param: str = typer.Option(..., "--from", help="The starting date and time of the requested data in any [ISO"),
316
+ to: str = typer.Option(..., "--to", help="The ending date and time of the requested data in any [ISO 8"),
317
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
318
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
319
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
320
+ debug: bool = typer.Option(False, "--debug"),
321
+ ):
322
+ """List Cluster Redirect details."""
323
+ api = get_api(debug=debug)
324
+ url = f"https://webexapis.com/v1/videoMesh/callRedirects"
325
+ params = {}
326
+ if from_param is not None:
327
+ params["from"] = from_param
328
+ if to is not None:
329
+ params["to"] = to
330
+ if limit > 0:
331
+ params["max"] = limit
332
+ if offset > 0:
333
+ params["start"] = offset
334
+ org_id = get_org_id()
335
+ if org_id is not None:
336
+ params["orgId"] = org_id
337
+ result = None
338
+ try:
339
+ result = api.session.rest_get(url, params=params)
340
+ except WebexError as e:
341
+ handle_rest_error(e)
342
+ result = result or []
343
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
344
+ if output == "json":
345
+ print_json(items)
346
+ else:
347
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name')], limit=limit)
348
+
349
+
350
+
351
+ @app.command("list-call-redirects-clusters")
352
+ def list_call_redirects_clusters(
353
+ from_param: str = typer.Option(..., "--from", help="The starting date and time of the requested data in any [ISO"),
354
+ to: str = typer.Option(..., "--to", help="The ending date and time of the requested data in any [ISO 8"),
355
+ cluster_id: str = typer.Option(..., "--cluster-id", help="The unique Video Mesh Cluster ID."),
356
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
357
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
358
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
359
+ debug: bool = typer.Option(False, "--debug"),
360
+ ):
361
+ """Get Cluster Redirect details."""
362
+ api = get_api(debug=debug)
363
+ url = f"https://webexapis.com/v1/videoMesh/clusters/callRedirects"
364
+ params = {}
365
+ if from_param is not None:
366
+ params["from"] = from_param
367
+ if to is not None:
368
+ params["to"] = to
369
+ if cluster_id is not None:
370
+ params["clusterId"] = cluster_id
371
+ if limit > 0:
372
+ params["max"] = limit
373
+ if offset > 0:
374
+ params["start"] = offset
375
+ result = None
376
+ try:
377
+ result = api.session.rest_get(url, params=params)
378
+ except WebexError as e:
379
+ handle_rest_error(e)
380
+ result = result or []
381
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
382
+ if output == "json":
383
+ print_json(items)
384
+ else:
385
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name')], limit=limit)
386
+
387
+
388
+
389
+ @app.command("list-utilization-video-mesh")
390
+ def list_utilization_video_mesh(
391
+ from_param: str = typer.Option(..., "--from", help="The starting date and time of the requested data in any [ISO"),
392
+ to: str = typer.Option(..., "--to", help="The ending date and time of the requested data in any [ISO 8"),
393
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
394
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
395
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
396
+ debug: bool = typer.Option(False, "--debug"),
397
+ ):
398
+ """List Clusters Utilization."""
399
+ api = get_api(debug=debug)
400
+ url = f"https://webexapis.com/v1/videoMesh/utilization"
401
+ params = {}
402
+ if from_param is not None:
403
+ params["from"] = from_param
404
+ if to is not None:
405
+ params["to"] = to
406
+ if limit > 0:
407
+ params["max"] = limit
408
+ if offset > 0:
409
+ params["start"] = offset
410
+ org_id = get_org_id()
411
+ if org_id is not None:
412
+ params["orgId"] = org_id
413
+ result = None
414
+ try:
415
+ result = api.session.rest_get(url, params=params)
416
+ except WebexError as e:
417
+ handle_rest_error(e)
418
+ result = result or []
419
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
420
+ if output == "json":
421
+ print_json(items)
422
+ else:
423
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name')], limit=limit)
424
+
425
+
426
+
427
+ @app.command("list-utilization-clusters")
428
+ def list_utilization_clusters(
429
+ from_param: str = typer.Option(..., "--from", help="The starting date and time of the requested data in any [ISO"),
430
+ to: str = typer.Option(..., "--to", help="The ending date and time of the requested data in any [ISO 8"),
431
+ cluster_id: str = typer.Option(..., "--cluster-id", help="The unique Video Mesh Cluster ID."),
432
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
433
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
434
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
435
+ debug: bool = typer.Option(False, "--debug"),
436
+ ):
437
+ """Get Cluster Utilization details."""
438
+ api = get_api(debug=debug)
439
+ url = f"https://webexapis.com/v1/videoMesh/clusters/utilization"
440
+ params = {}
441
+ if from_param is not None:
442
+ params["from"] = from_param
443
+ if to is not None:
444
+ params["to"] = to
445
+ if cluster_id is not None:
446
+ params["clusterId"] = cluster_id
447
+ if limit > 0:
448
+ params["max"] = limit
449
+ if offset > 0:
450
+ params["start"] = offset
451
+ result = None
452
+ try:
453
+ result = api.session.rest_get(url, params=params)
454
+ except WebexError as e:
455
+ handle_rest_error(e)
456
+ result = result or []
457
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
458
+ if output == "json":
459
+ print_json(items)
460
+ else:
461
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name')], limit=limit)
462
+
463
+
464
+
465
+ @app.command("list-reachability-test")
466
+ def list_reachability_test(
467
+ trigger_type: str = typer.Option(..., "--trigger-type", help="Choices: OnDemand, Periodic, All"),
468
+ from_param: str = typer.Option(..., "--from", help="The start date and time of the requested data in any [ISO 86"),
469
+ to: str = typer.Option(..., "--to", help="The end date and time of the requested data in any [ISO 8601"),
470
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
471
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
472
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
473
+ debug: bool = typer.Option(False, "--debug"),
474
+ ):
475
+ """List Reachability Test results V2."""
476
+ api = get_api(debug=debug)
477
+ url = f"https://webexapis.com/v1/videoMesh/testResults/reachabilityTest"
478
+ params = {}
479
+ if trigger_type is not None:
480
+ params["triggerType"] = trigger_type
481
+ if from_param is not None:
482
+ params["from"] = from_param
483
+ if to is not None:
484
+ params["to"] = to
485
+ if limit > 0:
486
+ params["max"] = limit
487
+ if offset > 0:
488
+ params["start"] = offset
489
+ org_id = get_org_id()
490
+ if org_id is not None:
491
+ params["orgId"] = org_id
492
+ result = None
493
+ try:
494
+ result = api.session.rest_get(url, params=params)
495
+ except WebexError as e:
496
+ handle_rest_error(e)
497
+ result = result or []
498
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
499
+ if output == "json":
500
+ print_json(items)
501
+ else:
502
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name')], limit=limit)
503
+
504
+
505
+
506
+ @app.command("list-clusters-reachability-test")
507
+ def list_clusters_reachability_test(
508
+ cluster_id: str = typer.Option(..., "--cluster-id", help="Unique ID of the Video Mesh cluster."),
509
+ trigger_type: str = typer.Option(..., "--trigger-type", help="Choices: OnDemand, Periodic, All"),
510
+ from_param: str = typer.Option(..., "--from", help="The start date and time of the requested data in any [ISO 86"),
511
+ to: str = typer.Option(..., "--to", help="The end date and time of the requested data in any [ISO 8601"),
512
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
513
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
514
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
515
+ debug: bool = typer.Option(False, "--debug"),
516
+ ):
517
+ """Get Reachability Test results for cluster V2."""
518
+ api = get_api(debug=debug)
519
+ url = f"https://webexapis.com/v1/videoMesh/testResults/reachabilityTest/clusters"
520
+ params = {}
521
+ if cluster_id is not None:
522
+ params["clusterId"] = cluster_id
523
+ if trigger_type is not None:
524
+ params["triggerType"] = trigger_type
525
+ if from_param is not None:
526
+ params["from"] = from_param
527
+ if to is not None:
528
+ params["to"] = to
529
+ if limit > 0:
530
+ params["max"] = limit
531
+ if offset > 0:
532
+ params["start"] = offset
533
+ result = None
534
+ try:
535
+ result = api.session.rest_get(url, params=params)
536
+ except WebexError as e:
537
+ handle_rest_error(e)
538
+ result = result or []
539
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
540
+ if output == "json":
541
+ print_json(items)
542
+ else:
543
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name')], limit=limit)
544
+
545
+
546
+
547
+ @app.command("list-nodes-reachability-test")
548
+ def list_nodes_reachability_test(
549
+ node_id: str = typer.Option(..., "--node-id", help="Unique ID of the Video Mesh node."),
550
+ trigger_type: str = typer.Option(..., "--trigger-type", help="Choices: OnDemand, Periodic, All"),
551
+ from_param: str = typer.Option(..., "--from", help="The start date and time of the requested data in any [ISO 86"),
552
+ to: str = typer.Option(..., "--to", help="The end date and time of the requested data in any [ISO 8601"),
553
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
554
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
555
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
556
+ debug: bool = typer.Option(False, "--debug"),
557
+ ):
558
+ """Get Reachability Test results for node V2."""
559
+ api = get_api(debug=debug)
560
+ url = f"https://webexapis.com/v1/videoMesh/testResults/reachabilityTest/nodes"
561
+ params = {}
562
+ if node_id is not None:
563
+ params["nodeId"] = node_id
564
+ if trigger_type is not None:
565
+ params["triggerType"] = trigger_type
566
+ if from_param is not None:
567
+ params["from"] = from_param
568
+ if to is not None:
569
+ params["to"] = to
570
+ if limit > 0:
571
+ params["max"] = limit
572
+ if offset > 0:
573
+ params["start"] = offset
574
+ result = None
575
+ try:
576
+ result = api.session.rest_get(url, params=params)
577
+ except WebexError as e:
578
+ handle_rest_error(e)
579
+ result = result or []
580
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
581
+ if output == "json":
582
+ print_json(items)
583
+ else:
584
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name')], limit=limit)
585
+
586
+
587
+
588
+ @app.command("list-clusters-video-mesh")
589
+ def list_clusters_video_mesh(
590
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
591
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
592
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
593
+ debug: bool = typer.Option(False, "--debug"),
594
+ ):
595
+ """List Cluster Details."""
596
+ api = get_api(debug=debug)
597
+ url = f"https://webexapis.com/v1/videoMesh/clusters"
598
+ params = {}
599
+ if limit > 0:
600
+ params["max"] = limit
601
+ if offset > 0:
602
+ params["start"] = offset
603
+ org_id = get_org_id()
604
+ if org_id is not None:
605
+ params["orgId"] = org_id
606
+ result = None
607
+ try:
608
+ result = api.session.rest_get(url, params=params)
609
+ except WebexError as e:
610
+ handle_rest_error(e)
611
+ result = result or []
612
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
613
+ if output == "json":
614
+ print_json(items)
615
+ else:
616
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name')], limit=limit)
617
+
618
+
619
+
620
+ @app.command("show-clusters")
621
+ def show_clusters(
622
+ cluster_id: str = typer.Argument(help="clusterId"),
623
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
624
+ debug: bool = typer.Option(False, "--debug"),
625
+ ):
626
+ """Get Cluster Details."""
627
+ api = get_api(debug=debug)
628
+ url = f"https://webexapis.com/v1/videoMesh/clusters/{cluster_id}"
629
+ try:
630
+ result = api.session.rest_get(url)
631
+ except WebexError as e:
632
+ handle_rest_error(e)
633
+ if output == "json":
634
+ print_json(result)
635
+ else:
636
+ if isinstance(result, dict):
637
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
638
+ elif isinstance(result, list):
639
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
640
+ else:
641
+ print_json(result)
642
+
643
+
644
+
645
+ @app.command("create")
646
+ def create(
647
+ cluster_id: str = typer.Argument(help="clusterId"),
648
+ type_param: str = typer.Option(None, "--type", help="Choices: ReachabilityTest, NetworkTest, MediaHealthMonitorTest"),
649
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
650
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
651
+ debug: bool = typer.Option(False, "--debug"),
652
+ ):
653
+ """Trigger on-demand test for cluster\n\nExample --json-body:\n '{"type":"ReachabilityTest","nodes":["..."]}'."""
654
+ api = get_api(debug=debug)
655
+ url = f"https://webexapis.com/v1/videoMesh/triggerTest/clusters/{cluster_id}"
656
+ if json_body:
657
+ body = json.loads(json_body)
658
+ else:
659
+ body = {}
660
+ if type_param is not None:
661
+ body["type"] = type_param
662
+ try:
663
+ result = api.session.rest_post(url, json=body)
664
+ except WebexError as e:
665
+ handle_rest_error(e)
666
+ if output == "json":
667
+ print_json(result)
668
+ elif isinstance(result, dict) and "id" in result:
669
+ typer.echo(f"Created: {result['id']}")
670
+ elif not result or result == {}:
671
+ typer.echo("Created.")
672
+ else:
673
+ print_json(result)
674
+
675
+
676
+
677
+ @app.command("create-nodes")
678
+ def create_nodes(
679
+ node_id: str = typer.Argument(help="nodeId"),
680
+ type_param: str = typer.Option(None, "--type", help="Choices: ReachabilityTest, NetworkTest, MediaHealthMonitorTest"),
681
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
682
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
683
+ debug: bool = typer.Option(False, "--debug"),
684
+ ):
685
+ """Trigger on-demand test for node."""
686
+ api = get_api(debug=debug)
687
+ url = f"https://webexapis.com/v1/videoMesh/triggerTest/nodes/{node_id}"
688
+ if json_body:
689
+ body = json.loads(json_body)
690
+ else:
691
+ body = {}
692
+ if type_param is not None:
693
+ body["type"] = type_param
694
+ try:
695
+ result = api.session.rest_post(url, json=body)
696
+ except WebexError as e:
697
+ handle_rest_error(e)
698
+ if output == "json":
699
+ print_json(result)
700
+ elif isinstance(result, dict) and "id" in result:
701
+ typer.echo(f"Created: {result['id']}")
702
+ elif not result or result == {}:
703
+ typer.echo("Created.")
704
+ else:
705
+ print_json(result)
706
+
707
+
708
+
709
+ @app.command("list-test-status")
710
+ def list_test_status(
711
+ command_id: str = typer.Option(..., "--command-id", help="The unique command ID generated from Trigger on-demand test"),
712
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
713
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
714
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
715
+ debug: bool = typer.Option(False, "--debug"),
716
+ ):
717
+ """Get Triggered test status."""
718
+ api = get_api(debug=debug)
719
+ url = f"https://webexapis.com/v1/videoMesh/testStatus"
720
+ params = {}
721
+ if command_id is not None:
722
+ params["commandId"] = command_id
723
+ if limit > 0:
724
+ params["max"] = limit
725
+ if offset > 0:
726
+ params["start"] = offset
727
+ result = None
728
+ try:
729
+ result = api.session.rest_get(url, params=params)
730
+ except WebexError as e:
731
+ handle_rest_error(e)
732
+ result = result or []
733
+ items = result.get("nodes", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
734
+ if output == "json":
735
+ print_json(items)
736
+ else:
737
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name')], limit=limit)
738
+
739
+
740
+
741
+ @app.command("list-test-results")
742
+ def list_test_results(
743
+ command_id: str = typer.Option(..., "--command-id", help="The unique command ID generated from Trigger on-demand test"),
744
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
745
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
746
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
747
+ debug: bool = typer.Option(False, "--debug"),
748
+ ):
749
+ """Get Triggered test results."""
750
+ api = get_api(debug=debug)
751
+ url = f"https://webexapis.com/v1/videoMesh/testResults"
752
+ params = {}
753
+ if command_id is not None:
754
+ params["commandId"] = command_id
755
+ if limit > 0:
756
+ params["max"] = limit
757
+ if offset > 0:
758
+ params["start"] = offset
759
+ result = None
760
+ try:
761
+ result = api.session.rest_get(url, params=params)
762
+ except WebexError as e:
763
+ handle_rest_error(e)
764
+ result = result or []
765
+ items = result.get("results", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
766
+ if output == "json":
767
+ print_json(items)
768
+ else:
769
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name')], limit=limit)
770
+
771
+
772
+
773
+ @app.command("list-network-test")
774
+ def list_network_test(
775
+ trigger_type: str = typer.Option(..., "--trigger-type", help="Choices: OnDemand, Periodic, All"),
776
+ from_param: str = typer.Option(..., "--from", help="The start date and time of the requested data in any [ISO 86"),
777
+ to: str = typer.Option(..., "--to", help="The end date and time of the requested data in any [ISO 8601"),
778
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
779
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
780
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
781
+ debug: bool = typer.Option(False, "--debug"),
782
+ ):
783
+ """List Network Test results."""
784
+ api = get_api(debug=debug)
785
+ url = f"https://webexapis.com/v1/videoMesh/testResults/networkTest"
786
+ params = {}
787
+ if trigger_type is not None:
788
+ params["triggerType"] = trigger_type
789
+ if from_param is not None:
790
+ params["from"] = from_param
791
+ if to is not None:
792
+ params["to"] = to
793
+ if limit > 0:
794
+ params["max"] = limit
795
+ if offset > 0:
796
+ params["start"] = offset
797
+ org_id = get_org_id()
798
+ if org_id is not None:
799
+ params["orgId"] = org_id
800
+ result = None
801
+ try:
802
+ result = api.session.rest_get(url, params=params)
803
+ except WebexError as e:
804
+ handle_rest_error(e)
805
+ result = result or []
806
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
807
+ if output == "json":
808
+ print_json(items)
809
+ else:
810
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name')], limit=limit)
811
+
812
+
813
+
814
+ @app.command("list-clusters-network-test")
815
+ def list_clusters_network_test(
816
+ cluster_id: str = typer.Option(..., "--cluster-id", help="Unique ID of the Video Mesh cluster."),
817
+ trigger_type: str = typer.Option(..., "--trigger-type", help="Choices: OnDemand, Periodic, All"),
818
+ from_param: str = typer.Option(..., "--from", help="The start date and time of the requested data in any [ISO 86"),
819
+ to: str = typer.Option(..., "--to", help="The end date and time of the requested data in any [ISO 8601"),
820
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
821
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
822
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
823
+ debug: bool = typer.Option(False, "--debug"),
824
+ ):
825
+ """Get Network Test results for cluster."""
826
+ api = get_api(debug=debug)
827
+ url = f"https://webexapis.com/v1/videoMesh/testResults/networkTest/clusters"
828
+ params = {}
829
+ if cluster_id is not None:
830
+ params["clusterId"] = cluster_id
831
+ if trigger_type is not None:
832
+ params["triggerType"] = trigger_type
833
+ if from_param is not None:
834
+ params["from"] = from_param
835
+ if to is not None:
836
+ params["to"] = to
837
+ if limit > 0:
838
+ params["max"] = limit
839
+ if offset > 0:
840
+ params["start"] = offset
841
+ result = None
842
+ try:
843
+ result = api.session.rest_get(url, params=params)
844
+ except WebexError as e:
845
+ handle_rest_error(e)
846
+ result = result or []
847
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
848
+ if output == "json":
849
+ print_json(items)
850
+ else:
851
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name')], limit=limit)
852
+
853
+
854
+
855
+ @app.command("list-nodes-network-test")
856
+ def list_nodes_network_test(
857
+ node_id: str = typer.Option(..., "--node-id", help="Unique ID of the Video Mesh node."),
858
+ trigger_type: str = typer.Option(..., "--trigger-type", help="Choices: OnDemand, Periodic, All"),
859
+ from_param: str = typer.Option(..., "--from", help="The start date and time of the requested data in any [ISO 86"),
860
+ to: str = typer.Option(..., "--to", help="The end date and time of the requested data in any [ISO 8601"),
861
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
862
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
863
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
864
+ debug: bool = typer.Option(False, "--debug"),
865
+ ):
866
+ """Get Network Test results for node."""
867
+ api = get_api(debug=debug)
868
+ url = f"https://webexapis.com/v1/videoMesh/testResults/networkTest/nodes"
869
+ params = {}
870
+ if node_id is not None:
871
+ params["nodeId"] = node_id
872
+ if trigger_type is not None:
873
+ params["triggerType"] = trigger_type
874
+ if from_param is not None:
875
+ params["from"] = from_param
876
+ if to is not None:
877
+ params["to"] = to
878
+ if limit > 0:
879
+ params["max"] = limit
880
+ if offset > 0:
881
+ params["start"] = offset
882
+ result = None
883
+ try:
884
+ result = api.session.rest_get(url, params=params)
885
+ except WebexError as e:
886
+ handle_rest_error(e)
887
+ result = result or []
888
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
889
+ if output == "json":
890
+ print_json(items)
891
+ else:
892
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name')], limit=limit)
893
+
894
+
895
+
896
+ @app.command("list-client-type-distribution")
897
+ def list_client_type_distribution(
898
+ from_param: str = typer.Option(..., "--from", help="The start date and time of the requested data in any [ISO 86"),
899
+ to: str = typer.Option(..., "--to", help="The end date and time of the requested data in any [ISO 8601"),
900
+ device_type: str = typer.Option(..., "--device-type", help="Device type(s). - Possible values: `webexDevices` `webexAp"),
901
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
902
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
903
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
904
+ debug: bool = typer.Option(False, "--debug"),
905
+ ):
906
+ """List Cluster Client Type Distribution details."""
907
+ api = get_api(debug=debug)
908
+ url = f"https://webexapis.com/v1/videoMesh/clientTypeDistribution"
909
+ params = {}
910
+ if from_param is not None:
911
+ params["from"] = from_param
912
+ if to is not None:
913
+ params["to"] = to
914
+ if device_type is not None:
915
+ params["deviceType"] = device_type
916
+ if limit > 0:
917
+ params["max"] = limit
918
+ if offset > 0:
919
+ params["start"] = offset
920
+ org_id = get_org_id()
921
+ if org_id is not None:
922
+ params["orgId"] = org_id
923
+ result = None
924
+ try:
925
+ result = api.session.rest_get(url, params=params)
926
+ except WebexError as e:
927
+ handle_rest_error(e)
928
+ result = result or []
929
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
930
+ if output == "json":
931
+ print_json(items)
932
+ else:
933
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name')], limit=limit)
934
+
935
+
936
+
937
+ @app.command("list-clusters-client-type-distribution")
938
+ def list_clusters_client_type_distribution(
939
+ cluster_id: str = typer.Option(..., "--cluster-id", help="Unique ID of the Video Mesh cluster."),
940
+ from_param: str = typer.Option(..., "--from", help="The start date and time of the requested data in any [ISO 86"),
941
+ to: str = typer.Option(..., "--to", help="The end date and time of the requested data in any [ISO 8601"),
942
+ device_type: str = typer.Option(..., "--device-type", help="Device type(s). - Possible values: `webexDevices` `webe"),
943
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
944
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
945
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
946
+ debug: bool = typer.Option(False, "--debug"),
947
+ ):
948
+ """Get Cluster Client Type Distribution details."""
949
+ api = get_api(debug=debug)
950
+ url = f"https://webexapis.com/v1/videoMesh/clientTypeDistribution/clusters"
951
+ params = {}
952
+ if cluster_id is not None:
953
+ params["clusterId"] = cluster_id
954
+ if from_param is not None:
955
+ params["from"] = from_param
956
+ if to is not None:
957
+ params["to"] = to
958
+ if device_type is not None:
959
+ params["deviceType"] = device_type
960
+ if limit > 0:
961
+ params["max"] = limit
962
+ if offset > 0:
963
+ params["start"] = offset
964
+ result = None
965
+ try:
966
+ result = api.session.rest_get(url, params=params)
967
+ except WebexError as e:
968
+ handle_rest_error(e)
969
+ result = result or []
970
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
971
+ if output == "json":
972
+ print_json(items)
973
+ else:
974
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name')], limit=limit)
975
+
976
+
977
+
978
+ @app.command("list-event-thresholds")
979
+ def list_event_thresholds(
980
+ event_name: str = typer.Option(None, "--event-name", help="Choices: clusterCallsRedirected, orgCallsOverflowed"),
981
+ cluster_id: str = typer.Option(None, "--cluster-id", help="Unique ID of the Video Mesh Cluster."),
982
+ event_scope: str = typer.Option(None, "--event-scope", help="Choices: CLUSTER, ORG"),
983
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
984
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
985
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
986
+ debug: bool = typer.Option(False, "--debug"),
987
+ ):
988
+ """List Event Threshold Configuration."""
989
+ api = get_api(debug=debug)
990
+ url = f"https://webexapis.com/v1/videoMesh/eventThresholds"
991
+ params = {}
992
+ if event_name is not None:
993
+ params["eventName"] = event_name
994
+ if cluster_id is not None:
995
+ params["clusterId"] = cluster_id
996
+ if event_scope is not None:
997
+ params["eventScope"] = event_scope
998
+ if limit > 0:
999
+ params["max"] = limit
1000
+ if offset > 0:
1001
+ params["start"] = offset
1002
+ org_id = get_org_id()
1003
+ if org_id is not None:
1004
+ params["orgId"] = org_id
1005
+ result = None
1006
+ try:
1007
+ result = api.session.rest_get(url, params=params)
1008
+ except WebexError as e:
1009
+ handle_rest_error(e)
1010
+ result = result or []
1011
+ items = result.get("eventThresholds", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
1012
+ if output == "json":
1013
+ print_json(items)
1014
+ else:
1015
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name')], limit=limit)
1016
+
1017
+
1018
+
1019
+ @app.command("update")
1020
+ def update(
1021
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
1022
+ debug: bool = typer.Option(False, "--debug"),
1023
+ ):
1024
+ """Update Event Threshold Configuration\n\nExample --json-body:\n '{"eventThresholds":[{"eventThresholdId":"...","thresholdConfig":"..."}]}'."""
1025
+ api = get_api(debug=debug)
1026
+ url = f"https://webexapis.com/v1/videoMesh/eventThresholds"
1027
+ if json_body:
1028
+ body = json.loads(json_body)
1029
+ else:
1030
+ body = {}
1031
+ try:
1032
+ result = api.session.rest_patch(url, json=body)
1033
+ except WebexError as e:
1034
+ handle_rest_error(e)
1035
+ typer.echo(f"Updated.")
1036
+
1037
+
1038
+
1039
+ @app.command("show-event-thresholds")
1040
+ def show_event_thresholds(
1041
+ event_threshold_id: str = typer.Argument(help="eventThresholdId"),
1042
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
1043
+ debug: bool = typer.Option(False, "--debug"),
1044
+ ):
1045
+ """Get Event Threshold Configuration."""
1046
+ api = get_api(debug=debug)
1047
+ url = f"https://webexapis.com/v1/videoMesh/eventThresholds/{event_threshold_id}"
1048
+ try:
1049
+ result = api.session.rest_get(url)
1050
+ except WebexError as e:
1051
+ handle_rest_error(e)
1052
+ if output == "json":
1053
+ print_json(result)
1054
+ else:
1055
+ if isinstance(result, dict):
1056
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
1057
+ elif isinstance(result, list):
1058
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
1059
+ else:
1060
+ print_json(result)
1061
+
1062
+
1063
+
1064
+ @app.command("create-reset")
1065
+ def create_reset(
1066
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
1067
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
1068
+ debug: bool = typer.Option(False, "--debug"),
1069
+ ):
1070
+ """Reset Event Threshold Configuration\n\nExample --json-body:\n '{"eventThresholdIds":["..."]}'."""
1071
+ api = get_api(debug=debug)
1072
+ url = f"https://webexapis.com/v1/videoMesh/eventThresholds/reset"
1073
+ if json_body:
1074
+ body = json.loads(json_body)
1075
+ else:
1076
+ body = {}
1077
+ try:
1078
+ result = api.session.rest_post(url, json=body)
1079
+ except WebexError as e:
1080
+ handle_rest_error(e)
1081
+ if output == "json":
1082
+ print_json(result)
1083
+ elif isinstance(result, dict) and "id" in result:
1084
+ typer.echo(f"Created: {result['id']}")
1085
+ elif not result or result == {}:
1086
+ typer.echo("Created.")
1087
+ else:
1088
+ print_json(result)
1089
+
1090
+