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,494 @@
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 call-park.")
10
+
11
+
12
+ @app.command("list")
13
+ def cmd_list(
14
+ location_id: str = typer.Argument(help="locationId"),
15
+ order: str = typer.Option(None, "--order", help="Sort the list of call parks by name, either ASC or DSC. Defa"),
16
+ name: str = typer.Option(None, "--name", help="Return the list of call parks that contains the given name."),
17
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
18
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
19
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
20
+ debug: bool = typer.Option(False, "--debug"),
21
+ ):
22
+ """Read the List of Call Parks."""
23
+ api = get_api(debug=debug)
24
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/callParks"
25
+ params = {}
26
+ if order is not None:
27
+ params["order"] = order
28
+ if name is not None:
29
+ params["name"] = name
30
+ if limit > 0:
31
+ params["max"] = limit
32
+ if offset > 0:
33
+ params["start"] = offset
34
+ org_id = get_org_id()
35
+ if org_id is not None:
36
+ params["orgId"] = org_id
37
+ result = None
38
+ try:
39
+ result = api.session.rest_get(url, params=params)
40
+ except WebexError as e:
41
+ handle_rest_error(e)
42
+ result = result or []
43
+ items = result.get("callParks", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
44
+ if output == "json":
45
+ print_json(items)
46
+ else:
47
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name')], limit=limit)
48
+
49
+
50
+
51
+ @app.command("create")
52
+ def create(
53
+ location_id: str = typer.Argument(help="locationId"),
54
+ name: str = typer.Option(None, "--name", help="(required) Unique name for the call park. The maximum length is 80."),
55
+ park_on_agents_enabled: bool = typer.Option(None, "--park-on-agents-enabled/--no-park-on-agents-enabled", help="Whether or not the calls will be parked on agents as a desti"),
56
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
57
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
58
+ debug: bool = typer.Option(False, "--debug"),
59
+ ):
60
+ """Create a Call Park\n\nExample --json-body:\n '{"name":"...","recall":{"option":"ALERT_PARKING_USER_ONLY","huntGroupId":"..."},"agents":["..."],"parkOnAgentsEnabled":true,"callParkExtensions":["..."]}'."""
61
+ api = get_api(debug=debug)
62
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/callParks"
63
+ params = {}
64
+ org_id = get_org_id()
65
+ if org_id is not None:
66
+ params["orgId"] = org_id
67
+ if json_body:
68
+ body = json.loads(json_body)
69
+ else:
70
+ body = {}
71
+ if name is not None:
72
+ body["name"] = name
73
+ if park_on_agents_enabled is not None:
74
+ body["parkOnAgentsEnabled"] = park_on_agents_enabled
75
+ _missing = [f for f in ['name'] if f not in body or body[f] is None]
76
+ if _missing:
77
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
78
+ raise typer.Exit(1)
79
+ try:
80
+ result = api.session.rest_post(url, json=body, params=params)
81
+ except WebexError as e:
82
+ handle_rest_error(e)
83
+ if output == "json":
84
+ print_json(result)
85
+ elif isinstance(result, dict) and "id" in result:
86
+ typer.echo(f"Created: {result['id']}")
87
+ elif not result or result == {}:
88
+ typer.echo("Created.")
89
+ else:
90
+ print_json(result)
91
+
92
+
93
+
94
+ @app.command("show")
95
+ def show(
96
+ location_id: str = typer.Argument(help="locationId"),
97
+ call_park_id: str = typer.Argument(help="callParkId"),
98
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
99
+ debug: bool = typer.Option(False, "--debug"),
100
+ ):
101
+ """Get Details for a Call Park."""
102
+ api = get_api(debug=debug)
103
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/callParks/{call_park_id}"
104
+ params = {}
105
+ org_id = get_org_id()
106
+ if org_id is not None:
107
+ params["orgId"] = org_id
108
+ try:
109
+ result = api.session.rest_get(url, params=params)
110
+ except WebexError as e:
111
+ handle_rest_error(e)
112
+ if output == "json":
113
+ print_json(result)
114
+ else:
115
+ if isinstance(result, dict):
116
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
117
+ elif isinstance(result, list):
118
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
119
+ else:
120
+ print_json(result)
121
+
122
+
123
+
124
+ @app.command("update")
125
+ def update(
126
+ location_id: str = typer.Argument(help="locationId"),
127
+ call_park_id: str = typer.Argument(help="callParkId"),
128
+ name: str = typer.Option(None, "--name", help="Unique name for the call park. The maximum length is 80."),
129
+ park_on_agents_enabled: bool = typer.Option(None, "--park-on-agents-enabled/--no-park-on-agents-enabled", help="Whether or not the calls will be parked on agents as a desti"),
130
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
131
+ debug: bool = typer.Option(False, "--debug"),
132
+ ):
133
+ """Update a Call Park\n\nExample --json-body:\n '{"name":"...","recall":{"option":"ALERT_PARKING_USER_ONLY","huntGroupId":"..."},"agents":["..."],"parkOnAgentsEnabled":true,"callParkExtensions":["..."]}'."""
134
+ api = get_api(debug=debug)
135
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/callParks/{call_park_id}"
136
+ params = {}
137
+ org_id = get_org_id()
138
+ if org_id is not None:
139
+ params["orgId"] = org_id
140
+ if json_body:
141
+ body = json.loads(json_body)
142
+ else:
143
+ body = {}
144
+ if name is not None:
145
+ body["name"] = name
146
+ if park_on_agents_enabled is not None:
147
+ body["parkOnAgentsEnabled"] = park_on_agents_enabled
148
+ try:
149
+ result = api.session.rest_put(url, json=body, params=params)
150
+ except WebexError as e:
151
+ handle_rest_error(e)
152
+ typer.echo(f"Updated.")
153
+
154
+
155
+
156
+ @app.command("delete")
157
+ def delete(
158
+ location_id: str = typer.Argument(help="locationId"),
159
+ call_park_id: str = typer.Argument(help="callParkId"),
160
+ force: bool = typer.Option(False, "--force", help="Skip confirmation"),
161
+ debug: bool = typer.Option(False, "--debug"),
162
+ ):
163
+ """Delete a Call Park."""
164
+ if not force:
165
+ typer.confirm(f"Delete {call_park_id}?", abort=True)
166
+ api = get_api(debug=debug)
167
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/callParks/{call_park_id}"
168
+ params = {}
169
+ org_id = get_org_id()
170
+ if org_id is not None:
171
+ params["orgId"] = org_id
172
+ try:
173
+ api.session.rest_delete(url, params=params)
174
+ except WebexError as e:
175
+ handle_rest_error(e)
176
+ typer.echo(f"Deleted: {call_park_id}")
177
+
178
+
179
+
180
+ @app.command("list-available-users")
181
+ def list_available_users(
182
+ location_id: str = typer.Argument(help="locationId"),
183
+ call_park_name: str = typer.Option(None, "--call-park-name", help="Only return available agents from call parks with the matchi"),
184
+ name: str = typer.Option(None, "--name", help="Only return available agents with the matching name."),
185
+ phone_number: str = typer.Option(None, "--phone-number", help="Only return available agents with the matching primary numbe"),
186
+ order: str = typer.Option(None, "--order", help="Order the available agents according to the designated field"),
187
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
188
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
189
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
190
+ debug: bool = typer.Option(False, "--debug"),
191
+ ):
192
+ """Get available agents from Call Parks."""
193
+ api = get_api(debug=debug)
194
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/callParks/availableUsers"
195
+ params = {}
196
+ if call_park_name is not None:
197
+ params["callParkName"] = call_park_name
198
+ if name is not None:
199
+ params["name"] = name
200
+ if phone_number is not None:
201
+ params["phoneNumber"] = phone_number
202
+ if order is not None:
203
+ params["order"] = order
204
+ if limit > 0:
205
+ params["max"] = limit
206
+ if offset > 0:
207
+ params["start"] = offset
208
+ org_id = get_org_id()
209
+ if org_id is not None:
210
+ params["orgId"] = org_id
211
+ result = None
212
+ try:
213
+ result = api.session.rest_get(url, params=params)
214
+ except WebexError as e:
215
+ handle_rest_error(e)
216
+ result = result or []
217
+ items = result.get("agents", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
218
+ if output == "json":
219
+ print_json(items)
220
+ else:
221
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name')], limit=limit)
222
+
223
+
224
+
225
+ @app.command("list-available-recall-hunt-groups")
226
+ def list_available_recall_hunt_groups(
227
+ location_id: str = typer.Argument(help="locationId"),
228
+ name: str = typer.Option(None, "--name", help="Only return available recall hunt groups with the matching n"),
229
+ order: str = typer.Option(None, "--order", help="Order the available recall hunt groups according to the desi"),
230
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
231
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
232
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
233
+ debug: bool = typer.Option(False, "--debug"),
234
+ ):
235
+ """Get available recall hunt groups from Call Parks."""
236
+ api = get_api(debug=debug)
237
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/callParks/availableRecallHuntGroups"
238
+ params = {}
239
+ if name is not None:
240
+ params["name"] = name
241
+ if order is not None:
242
+ params["order"] = order
243
+ if limit > 0:
244
+ params["max"] = limit
245
+ if offset > 0:
246
+ params["start"] = offset
247
+ org_id = get_org_id()
248
+ if org_id is not None:
249
+ params["orgId"] = org_id
250
+ result = None
251
+ try:
252
+ result = api.session.rest_get(url, params=params)
253
+ except WebexError as e:
254
+ handle_rest_error(e)
255
+ result = result or []
256
+ items = result.get("huntGroups", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
257
+ if output == "json":
258
+ print_json(items)
259
+ else:
260
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name')], limit=limit)
261
+
262
+
263
+
264
+ @app.command("show-settings")
265
+ def show_settings(
266
+ location_id: str = typer.Argument(help="locationId"),
267
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
268
+ debug: bool = typer.Option(False, "--debug"),
269
+ ):
270
+ """Get Call Park Settings."""
271
+ api = get_api(debug=debug)
272
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/callParks/settings"
273
+ params = {}
274
+ org_id = get_org_id()
275
+ if org_id is not None:
276
+ params["orgId"] = org_id
277
+ try:
278
+ result = api.session.rest_get(url, params=params)
279
+ except WebexError as e:
280
+ handle_rest_error(e)
281
+ if output == "json":
282
+ print_json(result)
283
+ else:
284
+ if isinstance(result, dict):
285
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
286
+ elif isinstance(result, list):
287
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
288
+ else:
289
+ print_json(result)
290
+
291
+
292
+
293
+ @app.command("update-settings")
294
+ def update_settings(
295
+ location_id: str = typer.Argument(help="locationId"),
296
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
297
+ debug: bool = typer.Option(False, "--debug"),
298
+ ):
299
+ """Update Call Park settings\n\nExample --json-body:\n '{"callParkRecall":{"option":"ALERT_PARKING_USER_ONLY","huntGroupId":"..."},"callParkSettings":{"ringPattern":"NORMAL","recallTime":0,"huntWaitTime":0}}'."""
300
+ api = get_api(debug=debug)
301
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/callParks/settings"
302
+ params = {}
303
+ org_id = get_org_id()
304
+ if org_id is not None:
305
+ params["orgId"] = org_id
306
+ if json_body:
307
+ body = json.loads(json_body)
308
+ else:
309
+ body = {}
310
+ try:
311
+ result = api.session.rest_put(url, json=body, params=params)
312
+ except WebexError as e:
313
+ handle_rest_error(e)
314
+ typer.echo(f"Updated.")
315
+
316
+
317
+
318
+ @app.command("list-call-park-extensions")
319
+ def list_call_park_extensions(
320
+ location_id: str = typer.Option(None, "--location-id", help="Only return call park extensions with matching location ID."),
321
+ extension: str = typer.Option(None, "--extension", help="Only return call park extensions with the matching extension"),
322
+ location_name: str = typer.Option(None, "--location-name", help="Only return call park extensions with the matching extension"),
323
+ name: str = typer.Option(None, "--name", help="Only return call park extensions with the matching name."),
324
+ order: str = typer.Option(None, "--order", help="Order the available agents according to the designated field"),
325
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
326
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
327
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
328
+ debug: bool = typer.Option(False, "--debug"),
329
+ ):
330
+ """Read the List of Call Park Extensions."""
331
+ api = get_api(debug=debug)
332
+ url = f"https://webexapis.com/v1/telephony/config/callParkExtensions"
333
+ params = {}
334
+ if location_id is not None:
335
+ params["locationId"] = location_id
336
+ if extension is not None:
337
+ params["extension"] = extension
338
+ if location_name is not None:
339
+ params["locationName"] = location_name
340
+ if name is not None:
341
+ params["name"] = name
342
+ if order is not None:
343
+ params["order"] = order
344
+ if limit > 0:
345
+ params["max"] = limit
346
+ if offset > 0:
347
+ params["start"] = offset
348
+ org_id = get_org_id()
349
+ if org_id is not None:
350
+ params["orgId"] = org_id
351
+ try:
352
+ if limit > 0:
353
+ result = api.session.rest_get(url, params=params)
354
+ result = result or {}
355
+ items = result.get("callParkExtensions", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
356
+ else:
357
+ items = list(api.session.follow_pagination(url=url, params=params, item_key="callParkExtensions"))
358
+ except WebexError as e:
359
+ handle_rest_error(e)
360
+ if output == "json":
361
+ print_json(items)
362
+ else:
363
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name')], limit=limit)
364
+
365
+
366
+
367
+ @app.command("show-call-park-extensions")
368
+ def show_call_park_extensions(
369
+ location_id: str = typer.Argument(help="locationId"),
370
+ call_park_extension_id: str = typer.Argument(help="callParkExtensionId"),
371
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
372
+ debug: bool = typer.Option(False, "--debug"),
373
+ ):
374
+ """Get Details for a Call Park Extension."""
375
+ api = get_api(debug=debug)
376
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/callParkExtensions/{call_park_extension_id}"
377
+ params = {}
378
+ org_id = get_org_id()
379
+ if org_id is not None:
380
+ params["orgId"] = org_id
381
+ try:
382
+ result = api.session.rest_get(url, params=params)
383
+ except WebexError as e:
384
+ handle_rest_error(e)
385
+ if output == "json":
386
+ print_json(result)
387
+ else:
388
+ if isinstance(result, dict):
389
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
390
+ elif isinstance(result, list):
391
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
392
+ else:
393
+ print_json(result)
394
+
395
+
396
+
397
+ @app.command("update-call-park-extensions")
398
+ def update_call_park_extensions(
399
+ location_id: str = typer.Argument(help="locationId"),
400
+ call_park_extension_id: str = typer.Argument(help="callParkExtensionId"),
401
+ name: str = typer.Option(None, "--name", help="Name for the call park extension. The maximum length is 30."),
402
+ extension: str = typer.Option(None, "--extension", help="Unique extension which will be assigned to call park extensi"),
403
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
404
+ debug: bool = typer.Option(False, "--debug"),
405
+ ):
406
+ """Update a Call Park Extension."""
407
+ api = get_api(debug=debug)
408
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/callParkExtensions/{call_park_extension_id}"
409
+ params = {}
410
+ org_id = get_org_id()
411
+ if org_id is not None:
412
+ params["orgId"] = org_id
413
+ if json_body:
414
+ body = json.loads(json_body)
415
+ else:
416
+ body = {}
417
+ if name is not None:
418
+ body["name"] = name
419
+ if extension is not None:
420
+ body["extension"] = extension
421
+ try:
422
+ result = api.session.rest_put(url, json=body, params=params)
423
+ except WebexError as e:
424
+ handle_rest_error(e)
425
+ typer.echo(f"Updated.")
426
+
427
+
428
+
429
+ @app.command("delete-call-park-extensions")
430
+ def delete_call_park_extensions(
431
+ location_id: str = typer.Argument(help="locationId"),
432
+ call_park_extension_id: str = typer.Argument(help="callParkExtensionId"),
433
+ force: bool = typer.Option(False, "--force", help="Skip confirmation"),
434
+ debug: bool = typer.Option(False, "--debug"),
435
+ ):
436
+ """Delete a Call Park Extension."""
437
+ if not force:
438
+ typer.confirm(f"Delete {call_park_extension_id}?", abort=True)
439
+ api = get_api(debug=debug)
440
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/callParkExtensions/{call_park_extension_id}"
441
+ params = {}
442
+ org_id = get_org_id()
443
+ if org_id is not None:
444
+ params["orgId"] = org_id
445
+ try:
446
+ api.session.rest_delete(url, params=params)
447
+ except WebexError as e:
448
+ handle_rest_error(e)
449
+ typer.echo(f"Deleted: {call_park_extension_id}")
450
+
451
+
452
+
453
+ @app.command("create-call-park-extensions")
454
+ def create_call_park_extensions(
455
+ location_id: str = typer.Argument(help="locationId"),
456
+ name: str = typer.Option(None, "--name", help="(required) Name for the call park extension. The maximum length is 30."),
457
+ extension: str = typer.Option(None, "--extension", help="(required) Unique extension which will be assigned to call park extensi"),
458
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
459
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
460
+ debug: bool = typer.Option(False, "--debug"),
461
+ ):
462
+ """Create a Call Park Extension."""
463
+ api = get_api(debug=debug)
464
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/callParkExtensions"
465
+ params = {}
466
+ org_id = get_org_id()
467
+ if org_id is not None:
468
+ params["orgId"] = org_id
469
+ if json_body:
470
+ body = json.loads(json_body)
471
+ else:
472
+ body = {}
473
+ if name is not None:
474
+ body["name"] = name
475
+ if extension is not None:
476
+ body["extension"] = extension
477
+ _missing = [f for f in ['name', 'extension'] if f not in body or body[f] is None]
478
+ if _missing:
479
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
480
+ raise typer.Exit(1)
481
+ try:
482
+ result = api.session.rest_post(url, json=body, params=params)
483
+ except WebexError as e:
484
+ handle_rest_error(e)
485
+ if output == "json":
486
+ print_json(result)
487
+ elif isinstance(result, dict) and "id" in result:
488
+ typer.echo(f"Created: {result['id']}")
489
+ elif not result or result == {}:
490
+ typer.echo("Created.")
491
+ else:
492
+ print_json(result)
493
+
494
+