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,227 @@
1
+ """Device mapper: CUCM Phones -> Webex Calling Devices.
2
+
3
+ Maps CUCM phone (SEP) devices to CanonicalDevice objects with four-tier
4
+ model compatibility classification. Skips common-area phones (those go to
5
+ workspace_mapper).
6
+
7
+ (from 03b-transform-mappers.md §4, device_mapper)
8
+
9
+ Cross-ref reads:
10
+ device_in_pool (Device -> DevicePool) — resolve pool
11
+ device_pool_to_location (DevicePool -> Location) — resolve location
12
+ device_has_dn (Device -> DN) — line appearances
13
+ device_owned_by_user (Device -> EndUser) — owner
14
+
15
+ Decisions generated:
16
+ DEVICE_INCOMPATIBLE — phone model in Incompatible tier
17
+
18
+ Convertible devices (``DeviceCompatibilityTier.CONVERTIBLE``) do NOT produce a
19
+ decision. Convertibility is a model classification; the planner unconditionally
20
+ emits a ``device:create_activation_code`` op for every convertible device.
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ import logging
26
+ from typing import Any
27
+
28
+ from wxcli.migration.models import (
29
+ CanonicalDevice,
30
+ DecisionType,
31
+ DeviceCompatibilityTier,
32
+ MapperResult,
33
+ MigrationStatus,
34
+ )
35
+ from wxcli.migration.store import MigrationStore
36
+ from wxcli.migration.transform.cross_reference import classify_phone_model
37
+ from wxcli.migration.transform.mappers.base import (
38
+ Mapper,
39
+ accept_option,
40
+ decision_to_store_dict,
41
+ extract_provenance,
42
+ manual_option,
43
+ skip_option,
44
+ )
45
+
46
+ logger = logging.getLogger(__name__)
47
+
48
+ # PhoneOS phones: 9800-series + 8875 use cloud deviceId ("cloud" surface).
49
+ # Classic MPP (6800-series, 7800-series, 8800-series) use callingDeviceId ("telephony").
50
+ from wxcli.migration.phone_models import PHONEOS_MODEL_NUMBERS as _CLOUD_SURFACE_SUBSTRINGS
51
+
52
+
53
+ class DeviceMapper(Mapper):
54
+ """Maps CUCM Phones to Webex Calling Devices.
55
+
56
+ Skips common-area phones (is_common_area=True in pre_migration_state) —
57
+ those are handled by workspace_mapper.
58
+
59
+ (from 03b-transform-mappers.md §4)
60
+ """
61
+
62
+ name = "device_mapper"
63
+ depends_on = ["location_mapper"]
64
+
65
+ def map(self, store: MigrationStore) -> MapperResult:
66
+ """Read normalized phone objects and produce CanonicalDevice objects."""
67
+ result = MapperResult()
68
+
69
+ for phone_data in store.get_objects("phone"):
70
+ phone_id = phone_data["canonical_id"]
71
+ state = phone_data.get("pre_migration_state") or {}
72
+
73
+ # Skip common-area phones — workspace_mapper handles those
74
+ # (from 03b-transform-mappers.md §4: "does NOT process common-area phones")
75
+ if state.get("is_common_area", False):
76
+ continue
77
+
78
+ # --- Model classification ---
79
+ # Uses classify_phone_model() from cross_reference.py
80
+ # (from 03b-transform-mappers.md §4: phone model compatibility table)
81
+ model = state.get("model")
82
+ protocol = state.get("protocol", "SIP")
83
+
84
+ # SCCP-only phones are classified as Incompatible regardless of model
85
+ # (from 03b-transform-mappers.md §4: "SCCP-only phones classified as Incompatible")
86
+ if protocol and protocol.upper() == "SCCP":
87
+ compatibility_tier = DeviceCompatibilityTier.INCOMPATIBLE
88
+ else:
89
+ compatibility_tier = classify_phone_model(model)
90
+
91
+ # --- MAC extraction ---
92
+ # Strip "SEP" prefix from device name to get 12 hex digits
93
+ # (from 03b-transform-mappers.md §4: "Extract 12 hex digits after SEP prefix")
94
+ device_name = state.get("name", phone_id.replace("phone:", ""))
95
+ mac = None
96
+ if device_name.upper().startswith("SEP"):
97
+ mac = device_name[3:].upper()
98
+ elif len(device_name) == 12 and all(c in "0123456789ABCDEFabcdef" for c in device_name):
99
+ mac = device_name.upper()
100
+
101
+ # Cross-refs link device:{name}, not phone:{name}. Derive the device ID.
102
+ device_id = f"device:{device_name}"
103
+
104
+ # --- Location resolution ---
105
+ # Chain: device -> device_in_pool -> device_pool_to_location
106
+ # (from 03b-transform-mappers.md §4: cross-ref dependencies)
107
+ location_canonical_id = store.resolve_chain(
108
+ device_id, "device_in_pool", "device_pool_to_location"
109
+ )
110
+
111
+ # --- Owner resolution ---
112
+ # (from 03b-transform-mappers.md §4: "device_owned_by_user")
113
+ owner_refs = store.find_cross_refs(device_id, "device_owned_by_user")
114
+ owner_canonical_id = owner_refs[0] if owner_refs else None
115
+
116
+ # --- Line appearances ---
117
+ # (from 03b-transform-mappers.md §4: "line appearances stored for post-creation config")
118
+ dn_refs = store.find_cross_refs(device_id, "device_has_dn")
119
+ line_appearances = state.get("line_appearances", [])
120
+
121
+ # --- Display name ---
122
+ display_name = state.get("description") or device_name
123
+
124
+ # --- Device ID surface ---
125
+ # PhoneOS phones (9800-series, 8875) use cloud deviceId; all others use callingDeviceId.
126
+ device_id_surface = "cloud" if any(s in (model or "") for s in _CLOUD_SURFACE_SUBSTRINGS) else "telephony"
127
+
128
+ # --- Build CanonicalDevice ---
129
+ device = CanonicalDevice(
130
+ canonical_id=f"device:{device_name}",
131
+ provenance=extract_provenance(phone_data),
132
+ status=MigrationStatus.ANALYZED,
133
+ mac=mac,
134
+ model=model,
135
+ compatibility_tier=compatibility_tier,
136
+ display_name=display_name,
137
+ owner_canonical_id=owner_canonical_id,
138
+ location_canonical_id=location_canonical_id,
139
+ line_appearances=line_appearances,
140
+ cucm_protocol=protocol,
141
+ cucm_device_name=device_name,
142
+ device_id_surface=device_id_surface,
143
+ )
144
+
145
+ store.upsert_object(device)
146
+ result.objects_created += 1
147
+
148
+ # --- Generate decisions for non-native devices ---
149
+ if compatibility_tier == DeviceCompatibilityTier.INFRASTRUCTURE:
150
+ # CTI Ports, CER, gateways, media resources — CUCM infrastructure,
151
+ # not user devices. Noted in inventory but no migration action needed.
152
+ # No decision generated — these are silently excluded from the plan.
153
+ pass
154
+
155
+ elif compatibility_tier == DeviceCompatibilityTier.DECT:
156
+ # DECT handset — hardware is Webex-compatible but requires DECT
157
+ # network provisioning (Phase 2), not standard phone activation.
158
+ # No decision generated — the hardware itself is fine.
159
+ pass
160
+
161
+ elif compatibility_tier == DeviceCompatibilityTier.WEBEX_APP:
162
+ # Software phones (Jabber, CSF, Dual Mode, IP Communicator) transition
163
+ # to Webex App. User keeps their number/extension, no device record needed
164
+ # in Webex — Webex App just works with a Calling license.
165
+ decision = self._create_decision(
166
+ store=store,
167
+ decision_type=DecisionType.DEVICE_INCOMPATIBLE,
168
+ severity="INFO",
169
+ summary=(
170
+ f"Soft client '{device_name}' ({model}) transitions to Webex App — "
171
+ f"no device migration needed"
172
+ ),
173
+ context={
174
+ "device_id": device.canonical_id,
175
+ "device_name": device_name,
176
+ "model": model,
177
+ "protocol": protocol,
178
+ "compatibility_tier": compatibility_tier.value,
179
+ "webex_app_transition": True,
180
+ },
181
+ options=[
182
+ accept_option(
183
+ "User gets Webex Calling license — Webex App replaces "
184
+ f"{model}. Number/extension preserved for PSTN dialing."
185
+ ),
186
+ manual_option("User also needs a physical phone (provision separately)"),
187
+ ],
188
+ affected_objects=[device.canonical_id],
189
+ )
190
+ store.save_decision(decision_to_store_dict(decision))
191
+ result.decisions.append(decision)
192
+
193
+ elif compatibility_tier == DeviceCompatibilityTier.INCOMPATIBLE:
194
+ decision = self._create_decision(
195
+ store=store,
196
+ decision_type=DecisionType.DEVICE_INCOMPATIBLE,
197
+ severity="HIGH",
198
+ summary=(
199
+ f"Device '{device_name}' (model: {model or 'unknown'}, "
200
+ f"protocol: {protocol}) is incompatible with Webex Calling"
201
+ ),
202
+ context={
203
+ "device_id": device.canonical_id,
204
+ "device_name": device_name,
205
+ "model": model,
206
+ "protocol": protocol,
207
+ "compatibility_tier": compatibility_tier.value,
208
+ },
209
+ options=[
210
+ skip_option("Migrate user without device — user must use Webex app or get new phone"),
211
+ manual_option("Replace with compatible MPP phone (68xx series recommended)"),
212
+ ],
213
+ affected_objects=[device.canonical_id],
214
+ )
215
+ store.save_decision(decision_to_store_dict(decision))
216
+ result.decisions.append(decision)
217
+
218
+ elif compatibility_tier == DeviceCompatibilityTier.CONVERTIBLE:
219
+ # No decision produced. Convertibility is a phone model
220
+ # classification, not an operator choice. The planner
221
+ # unconditionally emits a device:create_activation_code op
222
+ # for convertible devices.
223
+ pass
224
+
225
+ return result
226
+
227
+
@@ -0,0 +1,190 @@
1
+ """DeviceProfileMapper — CUCM Extension Mobility profiles → Webex hot desking advisory.
2
+
3
+ Reads device_profile objects from the store, resolves user ownership
4
+ (owner is the user whose default device profile this is), and produces
5
+ CanonicalDeviceProfile objects. If the user has a workspace at the same location,
6
+ the mapper flags it for hot desking enablement. If not, it produces a
7
+ FEATURE_APPROXIMATION decision.
8
+
9
+ CUCM EM is architecturally richer — profiles carry lines, speed dials, and services.
10
+ Webex hot desking is login/logout with the user's primary line only.
11
+
12
+ (from tier2-enterprise-expansion.md §5)
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import logging
18
+ from datetime import datetime, timezone
19
+ from typing import Any
20
+
21
+ from wxcli.migration.models import (
22
+ CanonicalDeviceProfile,
23
+ DecisionType,
24
+ MigrationObject,
25
+ MigrationStatus,
26
+ MapperResult,
27
+ Provenance,
28
+ )
29
+ from wxcli.migration.store import MigrationStore
30
+ from wxcli.migration.transform.mappers.base import (
31
+ Mapper,
32
+ accept_option,
33
+ extract_provenance,
34
+ manual_option,
35
+ skip_option,
36
+ )
37
+
38
+ logger = logging.getLogger(__name__)
39
+
40
+
41
+ class DeviceProfileMapper(Mapper):
42
+ """Map CUCM Device Profiles to hot desking advisory objects.
43
+
44
+ Tier 2 expansion: produces CanonicalDeviceProfile objects and
45
+ FEATURE_APPROXIMATION decisions for EM → hot desking mapping.
46
+ """
47
+
48
+ name = "device_profile_mapper"
49
+ depends_on = ["user_mapper", "workspace_mapper", "location_mapper"]
50
+
51
+ def map(self, store: MigrationStore) -> MapperResult:
52
+ result = MapperResult()
53
+ hoteling_locations: dict[str, int] = {} # loc_cid -> profile count
54
+
55
+ for dp_data in store.get_objects("device_profile"):
56
+ state = dp_data.get("pre_migration_state") or {}
57
+ profile_name = state.get("profile_name") or ""
58
+ if not profile_name:
59
+ continue
60
+
61
+ lines = state.get("lines") or []
62
+ model = state.get("model") or ""
63
+ protocol = state.get("protocol") or ""
64
+ device_pool = state.get("device_pool_name") or ""
65
+ sd_count = state.get("speed_dial_count", 0)
66
+ blf_count = state.get("blf_count", 0)
67
+
68
+ user_cid = self._find_profile_owner(store, profile_name)
69
+
70
+ # Resolve location from device pool cross-ref
71
+ location_cid: str | None = None
72
+ if device_pool:
73
+ dp_cid = f"device_pool:{device_pool}"
74
+ loc_refs = store.find_cross_refs(dp_cid, "device_pool_to_location")
75
+ if loc_refs:
76
+ location_cid = loc_refs[0] if isinstance(loc_refs[0], str) else loc_refs[0].get("target_id")
77
+
78
+ prov = extract_provenance(dp_data)
79
+ dp = CanonicalDeviceProfile(
80
+ canonical_id=f"device_profile:{profile_name}",
81
+ provenance=prov,
82
+ status=MigrationStatus.ANALYZED,
83
+ profile_name=profile_name,
84
+ user_canonical_id=user_cid,
85
+ model=model,
86
+ protocol=protocol,
87
+ lines=lines,
88
+ device_pool_name=device_pool,
89
+ speed_dial_count=sd_count,
90
+ blf_count=blf_count,
91
+ hoteling_guest_enabled=user_cid is not None,
92
+ auto_logout_minutes=0,
93
+ location_canonical_id=location_cid,
94
+ )
95
+ store.upsert_object(dp)
96
+ result.objects_created += 1
97
+
98
+ # Track locations for hoteling_location object creation
99
+ if location_cid:
100
+ hoteling_locations[location_cid] = hoteling_locations.get(location_cid, 0) + 1
101
+
102
+ if user_cid:
103
+ store.add_cross_ref(user_cid, dp.canonical_id, "user_has_device_profile")
104
+
105
+ # Decision: EM has features Webex hot desking doesn't support
106
+ has_multi_line = len(lines) > 1
107
+ has_extra_features = sd_count > 0 or blf_count > 0
108
+
109
+ if has_multi_line or has_extra_features:
110
+ features_lost = []
111
+ if has_multi_line:
112
+ features_lost.append(f"{len(lines)} line(s) — Webex hot desking uses primary line only")
113
+ if sd_count > 0:
114
+ features_lost.append(f"{sd_count} speed dial(s)")
115
+ if blf_count > 0:
116
+ features_lost.append(f"{blf_count} BLF entr(ies)")
117
+
118
+ decision = self._create_decision(
119
+ store=store,
120
+ decision_type=DecisionType.FEATURE_APPROXIMATION,
121
+ severity="LOW",
122
+ summary=(
123
+ f"Device profile '{profile_name}' has features that "
124
+ f"Webex hot desking cannot replicate"
125
+ ),
126
+ context={
127
+ "profile_name": profile_name,
128
+ "user_id": user_cid,
129
+ "features_lost": features_lost,
130
+ "line_count": len(lines),
131
+ "speed_dial_count": sd_count,
132
+ "blf_count": blf_count,
133
+ "classification": "EXTENSION_MOBILITY",
134
+ },
135
+ options=[
136
+ accept_option("Enable hot desking — user gets primary line only, loses profile features"),
137
+ skip_option("Don't enable hot desking"),
138
+ manual_option("Admin creates workspace and configures manually"),
139
+ ],
140
+ affected_objects=[dp.canonical_id] + ([user_cid] if user_cid else []),
141
+ )
142
+ result.decisions.append(decision)
143
+
144
+ # Create hoteling_location objects for location-level voice portal config
145
+ for loc_cid, profile_count in hoteling_locations.items():
146
+ loc_obj = MigrationObject(
147
+ canonical_id=f"hoteling_location:{loc_cid}",
148
+ provenance=Provenance(
149
+ source_system="cucm",
150
+ source_id=loc_cid,
151
+ source_name="hoteling_location",
152
+ extracted_at=datetime.now(timezone.utc),
153
+ ),
154
+ status=MigrationStatus.ANALYZED,
155
+ pre_migration_state={
156
+ "location_canonical_id": loc_cid,
157
+ "em_profile_count": profile_count,
158
+ },
159
+ )
160
+ store.upsert_object(loc_obj)
161
+ result.objects_created += 1
162
+
163
+ return result
164
+
165
+ @staticmethod
166
+ def _find_profile_owner(store: MigrationStore, profile_name: str) -> str | None:
167
+ """Try to find the user who owns a device profile.
168
+
169
+ CUCM device profiles are typically named 'UDP-{userid}' or
170
+ '{model}-{userid}'. Also check cross-refs for user_has_device_profile
171
+ if already built.
172
+ """
173
+ # Check common naming patterns
174
+ lower_name = profile_name.lower()
175
+ for prefix in ("udp-", "dp-", "em-"):
176
+ if lower_name.startswith(prefix):
177
+ userid = profile_name[len(prefix):]
178
+ user_cid = f"user:{userid}"
179
+ if store.get_object(user_cid):
180
+ return user_cid
181
+
182
+ # Brute force: check all users for matching profile reference
183
+ # (expensive but covers non-standard naming)
184
+ for user_data in store.get_objects("user"):
185
+ state = user_data.get("pre_migration_state") or {}
186
+ default_profile = state.get("defaultProfile") or state.get("deviceProfile") or ""
187
+ if default_profile == profile_name:
188
+ return user_data["canonical_id"]
189
+
190
+ return None