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,263 @@
1
+ """EcbnMapper — produce per-entity ECBN configuration for E911 execution.
2
+
3
+ Reads CanonicalUser and CanonicalWorkspace objects and classifies each
4
+ entity's ECBN eligibility. No new AXL queries — uses existing cross-refs
5
+ and canonical line data.
6
+
7
+ Classification logic (from 2026-04-10-e911-ecbn-execution.md §4.1):
8
+ 1. Entity has exactly one DID -> DIRECT_LINE (auto-configured)
9
+ 2. Entity has multiple DIDs -> E911_ECBN_AMBIGUOUS decision
10
+ 3. Entity has zero DIDs -> LOCATION_ECBN (auto-configured)
11
+ 4. User location differs from device location -> E911_LOCATION_MISMATCH
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import logging
17
+
18
+ from wxcli.migration.models import (
19
+ CanonicalEcbnConfig,
20
+ DecisionOption,
21
+ DecisionType,
22
+ MapperResult,
23
+ MigrationStatus,
24
+ )
25
+ from wxcli.migration.store import MigrationStore
26
+ from wxcli.migration.transform.mappers.base import (
27
+ Mapper,
28
+ extract_provenance,
29
+ )
30
+
31
+ logger = logging.getLogger(__name__)
32
+
33
+
34
+ class EcbnMapper(Mapper):
35
+ """Classify each user/workspace by ECBN eligibility.
36
+
37
+ Depends on UserMapper, WorkspaceMapper, LocationMapper, LineMapper,
38
+ DeviceMapper — must run after all entity mappers have populated the store.
39
+ """
40
+
41
+ name = "ecbn_mapper"
42
+ depends_on = [
43
+ "user_mapper",
44
+ "workspace_mapper",
45
+ "location_mapper",
46
+ "line_mapper",
47
+ "device_mapper",
48
+ ]
49
+
50
+ def map(self, store: MigrationStore) -> MapperResult:
51
+ result = MapperResult()
52
+
53
+ # Process users
54
+ for user_data in store.get_objects("user"):
55
+ status = user_data.get("status")
56
+ if status in (MigrationStatus.SKIPPED.value, "skipped"):
57
+ continue
58
+ self._process_user(store, user_data, result)
59
+
60
+ # Process workspaces
61
+ for ws_data in store.get_objects("workspace"):
62
+ status = ws_data.get("status")
63
+ if status in (MigrationStatus.SKIPPED.value, "skipped"):
64
+ continue
65
+ self._process_workspace(store, ws_data, result)
66
+
67
+ return result
68
+
69
+ # ------------------------------------------------------------------
70
+ # User processing
71
+ # ------------------------------------------------------------------
72
+
73
+ def _process_user(
74
+ self,
75
+ store: MigrationStore,
76
+ user_data: dict,
77
+ result: MapperResult,
78
+ ) -> None:
79
+ user_cid = user_data["canonical_id"]
80
+ user_location = user_data.get("location_id")
81
+
82
+ # Collect all DIDs (E.164 numbers) from devices -> DNs -> lines
83
+ dids, device_locations = self._collect_user_dids(store, user_cid)
84
+ primary_did = dids[0] if dids else None
85
+
86
+ # Determine ECBN selection
87
+ if len(dids) >= 1:
88
+ selection = "DIRECT_LINE"
89
+ needs_loc = False
90
+ else:
91
+ selection = "LOCATION_ECBN"
92
+ needs_loc = True
93
+
94
+ cfg = CanonicalEcbnConfig(
95
+ canonical_id=f"ecbn_config:{user_cid}",
96
+ provenance=extract_provenance(user_data),
97
+ status=MigrationStatus.ANALYZED,
98
+ entity_type="user",
99
+ entity_canonical_id=user_cid,
100
+ location_canonical_id=user_location,
101
+ ecbn_selection=selection,
102
+ did_numbers=dids,
103
+ primary_did=primary_did,
104
+ needs_location_ecbn=needs_loc,
105
+ )
106
+ store.upsert_object(cfg)
107
+ result.objects_created += 1
108
+
109
+ # Multi-DID → ambiguous decision
110
+ if len(dids) >= 2:
111
+ options = [
112
+ DecisionOption(
113
+ id=f"did_{d}",
114
+ label=f"Use {d}",
115
+ impact=f"ECBN set to {d} (DIRECT_LINE)",
116
+ )
117
+ for d in dids
118
+ ]
119
+ options.append(DecisionOption(
120
+ id="location_ecbn",
121
+ label="Use location ECBN",
122
+ impact="ECBN set to LOCATION_ECBN",
123
+ ))
124
+ decision = self._create_decision(
125
+ store=store,
126
+ decision_type=DecisionType.E911_ECBN_AMBIGUOUS,
127
+ severity="HIGH",
128
+ summary=f"User {user_cid} has {len(dids)} DIDs — which is the ECBN?",
129
+ context={
130
+ "user_canonical_id": user_cid,
131
+ "did_numbers": dids,
132
+ "primary_did": primary_did,
133
+ "user_location": user_location,
134
+ },
135
+ options=options,
136
+ affected_objects=[cfg.canonical_id, user_cid],
137
+ )
138
+ result.decisions.append(decision)
139
+
140
+ # Location mismatch detection
141
+ if user_location and device_locations:
142
+ distinct_device_locs = {loc for loc in device_locations if loc}
143
+ if distinct_device_locs and user_location not in distinct_device_locs:
144
+ # Sort the set before picking — iteration order over sets
145
+ # depends on PYTHONHASHSEED and would produce nondeterministic
146
+ # fingerprints when a user has 2+ devices at different
147
+ # locations.
148
+ sorted_dev_locs = sorted(distinct_device_locs)
149
+ dev_loc = sorted_dev_locs[0]
150
+ options = [
151
+ DecisionOption(
152
+ id="use_user_location",
153
+ label=f"Use user's assigned location ({user_location})",
154
+ impact="ECBN resolves to user_location",
155
+ ),
156
+ DecisionOption(
157
+ id="use_device_location",
158
+ label=f"Use device's physical location ({dev_loc})",
159
+ impact="ECBN resolves to device_location",
160
+ ),
161
+ DecisionOption(
162
+ id="manual",
163
+ label="Operator must verify physical location",
164
+ impact="Requires manual verification",
165
+ ),
166
+ ]
167
+ decision = self._create_decision(
168
+ store=store,
169
+ decision_type=DecisionType.E911_LOCATION_MISMATCH,
170
+ severity="HIGH",
171
+ summary=f"User {user_cid} location differs from device location",
172
+ context={
173
+ "user_canonical_id": user_cid,
174
+ "user_location": user_location,
175
+ "device_location": dev_loc,
176
+ "device_locations": sorted_dev_locs,
177
+ },
178
+ options=options,
179
+ affected_objects=[cfg.canonical_id, user_cid],
180
+ )
181
+ result.decisions.append(decision)
182
+
183
+ def _collect_user_dids(
184
+ self,
185
+ store: MigrationStore,
186
+ user_cid: str,
187
+ ) -> tuple[list[str], list[str]]:
188
+ """Walk user -> devices -> DNs -> lines to collect DID numbers.
189
+
190
+ Returns (did_numbers, device_location_canonical_ids).
191
+ Dedupes DIDs (same DID on multiple devices counts once).
192
+ """
193
+ dids: list[str] = []
194
+ seen: set[str] = set()
195
+ device_locations: list[str] = []
196
+
197
+ device_cids = store.find_cross_refs(user_cid, "user_has_device")
198
+ for dev_cid in device_cids:
199
+ dev_data = store.get_object(dev_cid)
200
+ if dev_data:
201
+ dev_loc = dev_data.get("location_canonical_id")
202
+ if dev_loc:
203
+ device_locations.append(dev_loc)
204
+
205
+ dn_cids = store.find_cross_refs(dev_cid, "device_has_dn")
206
+ for dn_cid in dn_cids:
207
+ if not dn_cid.startswith("dn:"):
208
+ continue
209
+ line_cid = "line:" + dn_cid[len("dn:"):]
210
+ line = store.get_object(line_cid)
211
+ if not line:
212
+ continue
213
+ e164 = line.get("e164")
214
+ if e164 and e164 not in seen:
215
+ dids.append(e164)
216
+ seen.add(e164)
217
+
218
+ # Sort DIDs for deterministic ordering — fingerprint stability depends
219
+ # on this. store.find_cross_refs returns SQLite rows in insertion order,
220
+ # not by any semantic notion of "primary," so primary_did = dids[0] on
221
+ # the caller side must be derived from a stable sort.
222
+ dids.sort()
223
+ return dids, device_locations
224
+
225
+ # ------------------------------------------------------------------
226
+ # Workspace processing
227
+ # ------------------------------------------------------------------
228
+
229
+ def _process_workspace(
230
+ self,
231
+ store: MigrationStore,
232
+ ws_data: dict,
233
+ result: MapperResult,
234
+ ) -> None:
235
+ ws_cid = ws_data["canonical_id"]
236
+ phone_number = ws_data.get("phone_number")
237
+ location = ws_data.get("location_id")
238
+
239
+ if phone_number:
240
+ selection = "DIRECT_LINE"
241
+ dids = [phone_number]
242
+ primary = phone_number
243
+ needs_loc = False
244
+ else:
245
+ selection = "LOCATION_ECBN"
246
+ dids = []
247
+ primary = None
248
+ needs_loc = True
249
+
250
+ cfg = CanonicalEcbnConfig(
251
+ canonical_id=f"ecbn_config:{ws_cid}",
252
+ provenance=extract_provenance(ws_data),
253
+ status=MigrationStatus.ANALYZED,
254
+ entity_type="workspace",
255
+ entity_canonical_id=ws_cid,
256
+ location_canonical_id=location,
257
+ ecbn_selection=selection,
258
+ did_numbers=dids,
259
+ primary_did=primary,
260
+ needs_location_ecbn=needs_loc,
261
+ )
262
+ store.upsert_object(cfg)
263
+ result.objects_created += 1
@@ -0,0 +1,156 @@
1
+ """Maps CUCM executive/assistant pairings to Webex Executive/Assistant config.
2
+
3
+ Reads normalized exec_asst_pair objects from the store, groups by executive,
4
+ resolves assistant user canonical_ids, and produces CanonicalExecutiveAssistant
5
+ objects. Generates MISSING_DATA decisions when one side of a pair is not in
6
+ migration scope.
7
+
8
+ (from executive-assistant-migration spec §4c)
9
+ """
10
+ from __future__ import annotations
11
+
12
+ import logging
13
+ from collections import defaultdict
14
+ from typing import Any
15
+
16
+ from wxcli.migration.models import (
17
+ CanonicalExecutiveAssistant,
18
+ DecisionType,
19
+ MapperResult,
20
+ MigrationStatus,
21
+ )
22
+ from wxcli.migration.store import MigrationStore
23
+ from wxcli.migration.transform.mappers.base import (
24
+ Mapper,
25
+ decision_to_store_dict,
26
+ extract_provenance,
27
+ manual_option,
28
+ skip_option,
29
+ )
30
+
31
+ logger = logging.getLogger(__name__)
32
+
33
+
34
+ class ExecutiveAssistantMapper(Mapper):
35
+ """Maps CUCM executive/assistant pairs to Webex config objects."""
36
+
37
+ name = "executive_assistant_mapper"
38
+ depends_on = ["user_mapper"]
39
+
40
+ def map(self, store: MigrationStore) -> MapperResult:
41
+ result = MapperResult()
42
+
43
+ # Group pairs by executive userid
44
+ pairs_by_exec: dict[str, list[str]] = defaultdict(list)
45
+ for pair_data in store.get_objects("exec_asst_pair"):
46
+ state = pair_data.get("pre_migration_state") or {}
47
+ exec_userid = state.get("executive_userid")
48
+ asst_userid = state.get("assistant_userid")
49
+ if exec_userid and asst_userid:
50
+ pairs_by_exec[exec_userid].append(asst_userid)
51
+
52
+ if not pairs_by_exec:
53
+ return result
54
+
55
+ # Build settings lookup
56
+ settings_by_userid: dict[str, dict[str, Any]] = {}
57
+ for setting_data in store.get_objects("exec_setting"):
58
+ state = setting_data.get("pre_migration_state") or {}
59
+ userid = state.get("userid")
60
+ if userid:
61
+ settings_by_userid[userid] = state
62
+
63
+ # Process each executive
64
+ for exec_userid, asst_userids in pairs_by_exec.items():
65
+ exec_canonical_id = f"user:{exec_userid}"
66
+
67
+ # Verify executive exists in store
68
+ exec_obj = store.get_object(exec_canonical_id)
69
+ if exec_obj is None:
70
+ decision = self._create_decision(
71
+ store=store,
72
+ decision_type=DecisionType.MISSING_DATA,
73
+ severity="HIGH",
74
+ summary=(
75
+ f"Executive '{exec_userid}' not in migration scope \u2014 "
76
+ f"{len(asst_userids)} assistant pairing(s) cannot be migrated"
77
+ ),
78
+ context={
79
+ "missing_reason": "executive_assistant_broken_pair",
80
+ "missing_side": "executive",
81
+ "executive_userid": exec_userid,
82
+ "assistant_userids": asst_userids,
83
+ },
84
+ options=[
85
+ manual_option(
86
+ "Configure executive/assistant manually in Webex after migration"
87
+ ),
88
+ skip_option("Executive/assistant pairing not migrated"),
89
+ ],
90
+ affected_objects=[exec_canonical_id],
91
+ )
92
+ store.save_decision(decision_to_store_dict(decision))
93
+ result.decisions.append(decision)
94
+ continue
95
+
96
+ # Verify each assistant exists
97
+ valid_assistants: list[str] = []
98
+ for asst_userid in asst_userids:
99
+ asst_canonical_id = f"user:{asst_userid}"
100
+ asst_obj = store.get_object(asst_canonical_id)
101
+ if asst_obj is None:
102
+ decision = self._create_decision(
103
+ store=store,
104
+ decision_type=DecisionType.MISSING_DATA,
105
+ severity="HIGH",
106
+ summary=(
107
+ f"Assistant '{asst_userid}' for executive '{exec_userid}' "
108
+ f"not in migration scope"
109
+ ),
110
+ context={
111
+ "missing_reason": "executive_assistant_broken_pair",
112
+ "missing_side": "assistant",
113
+ "executive_userid": exec_userid,
114
+ "assistant_userid": asst_userid,
115
+ },
116
+ options=[
117
+ manual_option(
118
+ "Configure assistant manually in Webex after migration"
119
+ ),
120
+ skip_option("This assistant pairing not migrated"),
121
+ ],
122
+ affected_objects=[exec_canonical_id, asst_canonical_id],
123
+ )
124
+ store.save_decision(decision_to_store_dict(decision))
125
+ result.decisions.append(decision)
126
+ else:
127
+ valid_assistants.append(asst_canonical_id)
128
+
129
+ if not valid_assistants:
130
+ continue
131
+
132
+ # Read executive settings
133
+ exec_settings = settings_by_userid.get(exec_userid, {})
134
+
135
+ ea_obj = CanonicalExecutiveAssistant(
136
+ canonical_id=f"executive_assistant:{exec_userid}",
137
+ provenance=extract_provenance(exec_obj),
138
+ status=MigrationStatus.ANALYZED,
139
+ executive_canonical_id=exec_canonical_id,
140
+ assistant_canonical_ids=valid_assistants,
141
+ alerting_mode=exec_settings.get("alerting_mode", "SIMULTANEOUS"),
142
+ filter_enabled=bool(exec_settings.get("filter_enabled", False)),
143
+ filter_type=exec_settings.get("filter_type", "ALL_CALLS"),
144
+ screening_enabled=bool(exec_settings.get("screening_enabled", False)),
145
+ )
146
+
147
+ store.upsert_object(ea_obj)
148
+ result.objects_created += 1
149
+
150
+ store.add_cross_ref(
151
+ exec_canonical_id,
152
+ ea_obj.canonical_id,
153
+ "user_has_executive_assistant_config",
154
+ )
155
+
156
+ return result