vmware-aiops 2.4.2__tar.gz → 2.4.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/.claude-plugin/plugin.json +1 -1
  2. vmware_aiops-2.4.4/.github/workflows/windows-file-lock.yml +32 -0
  3. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/.mcp.json +1 -1
  4. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/PKG-INFO +11 -4
  5. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/README-CN.md +8 -2
  6. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/README.md +8 -2
  7. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/RELEASE_NOTES.md +20 -2
  8. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/SECURITY.md +2 -2
  9. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/openclaw.plugin.json +1 -1
  10. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/package.json +1 -1
  11. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/pyproject.toml +3 -2
  12. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/server.json +2 -2
  13. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/skills/vmware-aiops/SKILL.md +13 -7
  14. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/skills/vmware-aiops/references/capabilities.md +2 -0
  15. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/skills/vmware-aiops/references/setup-guide.md +5 -5
  16. vmware_aiops-2.4.4/tests/eval/regression/test_delegated_lookup_errors.py +70 -0
  17. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_mcp_frame_marks_failures.py +1 -1
  18. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_write_round_low_findings.py +1 -1
  19. vmware_aiops-2.4.4/tests/test_ambiguous_inventory_names.py +127 -0
  20. vmware_aiops-2.4.4/tests/test_executors_act_on_the_previewed_vm.py +221 -0
  21. vmware_aiops-2.4.4/tests/test_fsutil.py +53 -0
  22. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/test_power_off_and_preview_policy.py +1 -1
  23. vmware_aiops-2.4.4/tests/test_webhook_secret_logging.py +66 -0
  24. vmware_aiops-2.4.4/tests/windows_lock_check.py +125 -0
  25. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/uv.lock +12 -10
  26. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/__init__.py +1 -1
  27. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/cli/_common.py +2 -2
  28. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/mcp_server/_shared.py +16 -0
  29. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/mcp_server/tools/guest.py +7 -3
  30. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/mcp_server/tools/vm.py +12 -4
  31. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/notify/webhook.py +2 -7
  32. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/ops/guest_ops.py +28 -9
  33. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/ops/inventory.py +69 -17
  34. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/ops/planner.py +6 -3
  35. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/ops/vm_gate.py +5 -0
  36. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/ops/vm_lifecycle.py +64 -9
  37. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/scanner/scheduler.py +5 -4
  38. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/.clawhubignore +0 -0
  39. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/.env.example +0 -0
  40. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  41. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  42. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  43. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  44. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/.github/dependabot.yml +0 -0
  45. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/.gitignore +0 -0
  46. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/Dockerfile +0 -0
  47. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/LICENSE +0 -0
  48. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/config.example.yaml +0 -0
  49. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/docker-compose.yml +0 -0
  50. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/docs/integrations/continue.md +0 -0
  51. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/docs/integrations/cursor.md +0 -0
  52. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/docs/integrations/goose.md +0 -0
  53. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/docs/integrations/localcowork.md +0 -0
  54. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/docs/integrations/mcp-agent.md +0 -0
  55. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/docs/integrations/vscode-copilot.md +0 -0
  56. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/docs/plans/2026-03-09-plan-apply-design.md +0 -0
  57. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/examples/deploy.yaml +0 -0
  58. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/examples/mcp-configs/README.md +0 -0
  59. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/examples/mcp-configs/claude-code.json +0 -0
  60. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/examples/mcp-configs/continue.yaml +0 -0
  61. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/examples/mcp-configs/cursor.json +0 -0
  62. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/examples/mcp-configs/goose.json +0 -0
  63. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/examples/mcp-configs/localcowork.json +0 -0
  64. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/examples/mcp-configs/mcp-agent.yaml +0 -0
  65. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/examples/mcp-configs/vscode-copilot.json +0 -0
  66. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/examples/ollama-local-setup.md +0 -0
  67. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/skills/vmware-aiops/evals/evals.json +0 -0
  68. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/skills/vmware-aiops/references/agent-guardrails.md +0 -0
  69. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/skills/vmware-aiops/references/cli-reference.md +0 -0
  70. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/skills/vmware-aiops/references/investigation-protocol.md +0 -0
  71. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/smithery.yaml +0 -0
  72. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/__init__.py +0 -0
  73. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/conftest.py +0 -0
  74. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/__init__.py +0 -0
  75. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/capability/__init__.py +0 -0
  76. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/capability/_family.py +0 -0
  77. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/capability/_scores.json +0 -0
  78. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/capability/_scoring.py +0 -0
  79. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/capability/_skill.py +0 -0
  80. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/capability/conftest.py +0 -0
  81. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/capability/test_entity_reachability.py +0 -0
  82. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/capability/test_error_actionability.py +0 -0
  83. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/capability/test_tool_description_quality.py +0 -0
  84. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/capability/test_tool_manifest_budget.py +0 -0
  85. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/__init__.py +0 -0
  86. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/_diag_fakes.py +0 -0
  87. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/_pc_fakes.py +0 -0
  88. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_aiops_specific.py +0 -0
  89. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_alarm_health_scale_n1.py +0 -0
  90. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_atexit_handlers_do_not_accumulate.py +0 -0
  91. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_browse_ds_path_join.py +0 -0
  92. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_browse_sees_every_file.py +0 -0
  93. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_capability_grader.py +0 -0
  94. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_cli_destructive_guards.py +0 -0
  95. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_cli_writes_guarded.py +0 -0
  96. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_cluster_health_summary_delegation.py +0 -0
  97. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_code_review_fixes.py +0 -0
  98. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_config_path_resolution_is_shared.py +0 -0
  99. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_daemon_calls_are_audited.py +0 -0
  100. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_daemon_host_log_cycles.py +0 -0
  101. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_deploy_correctness.py +0 -0
  102. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_deploy_failures_are_failures.py +0 -0
  103. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_doctor_authenticates_every_target.py +0 -0
  104. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_documented_gates_match_the_registry.py +0 -0
  105. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_enum_params_match_implementation.py +0 -0
  106. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_env_secret_obfuscation.py +0 -0
  107. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_error_hints_fit_the_surface.py +0 -0
  108. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_event_sets_match_real_class_names.py +0 -0
  109. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_events_are_read_newest_first.py +0 -0
  110. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_guest_download_writes_the_local_disk.py +0 -0
  111. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_guest_username_is_explicit.py +0 -0
  112. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_host_log_scan_reads_real_logs.py +0 -0
  113. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_host_paths_protected.py +0 -0
  114. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_image_registry_cross_process.py +0 -0
  115. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_image_registry_legacy_rows.py +0 -0
  116. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_image_registry_per_target.py +0 -0
  117. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_instructions_name_targets.py +0 -0
  118. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_inventory_scale_issue31.py +0 -0
  119. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_linked_clone_failure_on_the_wire.py +0 -0
  120. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_list_envelope_conformance.py +0 -0
  121. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_list_plans_is_non_destructive.py +0 -0
  122. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_login_without_vsphere_role.py +0 -0
  123. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_ova_network_mapping.py +0 -0
  124. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_release_blockers.py +0 -0
  125. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_result_envelope.py +0 -0
  126. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_returned_failure_is_audited.py +0 -0
  127. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_session_probe_eviction.py +0 -0
  128. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_set_ttl_safety.py +0 -0
  129. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_snapshot_async.py +0 -0
  130. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_text_io_declares_encoding.py +0 -0
  131. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_tool_annotations_match_behaviour.py +0 -0
  132. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_unreachable_host_vmks.py +0 -0
  133. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_v1_5_25_blockers.py +0 -0
  134. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/eval/regression/test_vim_attribute_conformance.py +0 -0
  135. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/test_access_info.py +0 -0
  136. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/test_cluster_mgmt_sanitize.py +0 -0
  137. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/test_cluster_ttl_plan_gate.py +0 -0
  138. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/test_composite_tools_obey_policy.py +0 -0
  139. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/test_concurrent_local_state.py +0 -0
  140. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/test_config.py +0 -0
  141. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/test_drs_rules.py +0 -0
  142. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/test_filelock.py +0 -0
  143. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/test_gate_review_fixes.py +0 -0
  144. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/test_guest_tools_gate.py +0 -0
  145. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/test_host_network_mgmt.py +0 -0
  146. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/test_init_and_onboarding.py +0 -0
  147. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/test_migrate_compatibility_check.py +0 -0
  148. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/test_network_mgmt.py +0 -0
  149. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/test_no_destructive_ops.py +0 -0
  150. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/test_plan_gate_narrow_fixes.py +0 -0
  151. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/test_plan_rollback_final_fixes.py +0 -0
  152. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/test_plan_steps_obey_policy.py +0 -0
  153. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/test_policy_roles.py +0 -0
  154. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/test_reset_alarm_gate.py +0 -0
  155. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/test_results_name_their_target.py +0 -0
  156. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/test_safe_error_passthrough.py +0 -0
  157. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/test_session_pool.py +0 -0
  158. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/test_stop_signal_runs_atexit.py +0 -0
  159. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/test_vm_delete_blast_radius.py +0 -0
  160. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/tests/test_vm_tools_gate.py +0 -0
  161. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/_filelock.py +0 -0
  162. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/_fsutil.py +0 -0
  163. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/access_requirements.py +0 -0
  164. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/cli/__init__.py +0 -0
  165. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/cli/_root.py +0 -0
  166. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/cli/access.py +0 -0
  167. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/cli/alarm.py +0 -0
  168. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/cli/cluster.py +0 -0
  169. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/cli/deploy.py +0 -0
  170. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/cli/doctor.py +0 -0
  171. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/cli/hub.py +0 -0
  172. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/cli/investigate.py +0 -0
  173. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/cli/mcp_config.py +0 -0
  174. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/cli/plan.py +0 -0
  175. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/cli/scan.py +0 -0
  176. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/cli/summary.py +0 -0
  177. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/cli/vm.py +0 -0
  178. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/config.py +0 -0
  179. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/connection.py +0 -0
  180. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/doctor.py +0 -0
  181. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/init_wizard.py +0 -0
  182. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/mcp_server/__init__.py +0 -0
  183. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/mcp_server/__main__.py +0 -0
  184. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/mcp_server/server.py +0 -0
  185. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/mcp_server/tools/__init__.py +0 -0
  186. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/mcp_server/tools/access.py +0 -0
  187. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/mcp_server/tools/alarm.py +0 -0
  188. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/mcp_server/tools/cluster.py +0 -0
  189. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/mcp_server/tools/datastore.py +0 -0
  190. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/mcp_server/tools/deploy.py +0 -0
  191. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/mcp_server/tools/network.py +0 -0
  192. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/mcp_server/tools/plan.py +0 -0
  193. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/mcp_server/tools/summary.py +0 -0
  194. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/mcp_server/tools/ttl.py +0 -0
  195. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/notify/__init__.py +0 -0
  196. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/notify/audit.py +0 -0
  197. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/notify/logger.py +0 -0
  198. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/ops/__init__.py +0 -0
  199. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/ops/_paging.py +0 -0
  200. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/ops/alarm_mgmt.py +0 -0
  201. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/ops/cluster_gate.py +0 -0
  202. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/ops/cluster_mgmt.py +0 -0
  203. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/ops/datastore_browser.py +0 -0
  204. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/ops/gate.py +0 -0
  205. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/ops/guest_gate.py +0 -0
  206. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/ops/health.py +0 -0
  207. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/ops/host_network_mgmt.py +0 -0
  208. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/ops/iscsi_config.py +0 -0
  209. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/ops/network_mgmt.py +0 -0
  210. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/ops/ova_deploy.py +0 -0
  211. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/ops/plan_executor.py +0 -0
  212. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/ops/plan_gate.py +0 -0
  213. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/ops/step_policy.py +0 -0
  214. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/ops/ttl.py +0 -0
  215. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/ops/vm_delete_gate.py +0 -0
  216. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/ops/vm_deploy.py +0 -0
  217. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/policy_environment.py +0 -0
  218. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/policy_roles.py +0 -0
  219. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/scanner/__init__.py +0 -0
  220. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/scanner/alarm_scanner.py +0 -0
  221. {vmware_aiops-2.4.2 → vmware_aiops-2.4.4}/vmware_aiops/scanner/log_scanner.py +0 -0
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://anthropic.com/claude-code/plugin.schema.json",
3
3
  "name": "vmware-aiops",
4
4
  "displayName": "VMware AIops",
5
- "version": "2.4.2",
5
+ "version": "2.4.4",
6
6
  "description": "AI-powered VMware vCenter/ESXi VM lifecycle and deployment with 61 MCP tools.",
7
7
  "author": {
8
8
  "name": "Wei Zhou",
@@ -0,0 +1,32 @@
1
+ name: Windows file lock
2
+
3
+ on:
4
+ pull_request:
5
+ paths:
6
+ - 'vmware_aiops/_filelock.py'
7
+ - 'tests/windows_lock_check.py'
8
+ - '.github/workflows/windows-file-lock.yml'
9
+ push:
10
+ branches: [main]
11
+ paths:
12
+ - 'vmware_aiops/_filelock.py'
13
+ - 'tests/windows_lock_check.py'
14
+ - '.github/workflows/windows-file-lock.yml'
15
+ workflow_dispatch:
16
+
17
+ permissions:
18
+ contents: read
19
+
20
+ jobs:
21
+ real-msvcrt:
22
+ runs-on: windows-latest
23
+ timeout-minutes: 10
24
+ steps:
25
+ - uses: actions/checkout@v7
26
+ with:
27
+ persist-credentials: false
28
+ - uses: actions/setup-python@v7
29
+ with:
30
+ python-version: '3.12'
31
+ - name: Check four-process serialization, bounded timeout, and release
32
+ run: python tests/windows_lock_check.py vmware_aiops/_filelock.py
@@ -5,7 +5,7 @@
5
5
  "command": "uvx",
6
6
  "args": [
7
7
  "--from",
8
- "vmware-aiops==2.4.2",
8
+ "vmware-aiops==2.4.4",
9
9
  "vmware-aiops-mcp"
10
10
  ]
11
11
  }
@@ -1,16 +1,17 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: vmware-aiops
3
- Version: 2.4.2
3
+ Version: 2.4.4
4
4
  Summary: VMware vCenter/ESXi AI-powered VM lifecycle and deployment tool
5
5
  Project-URL: Homepage, https://github.com/vmware-skills/VMware-AIops
6
6
  Project-URL: Repository, https://github.com/vmware-skills/VMware-AIops
7
7
  Project-URL: Issues, https://github.com/vmware-skills/VMware-AIops/issues
8
8
  Project-URL: Changelog, https://github.com/vmware-skills/VMware-AIops/blob/main/RELEASE_NOTES.md
9
- Author-email: Wei Zhou <wei-wz.zhou@broadcom.com>
9
+ Author-email: Wei Zhou <zhouwei008@gmail.com>
10
10
  License-Expression: MIT
11
11
  License-File: LICENSE
12
12
  Requires-Python: >=3.10
13
13
  Requires-Dist: apscheduler<4.0,>=3.10
14
+ Requires-Dist: certifi>=2026.10.19
14
15
  Requires-Dist: httpx<1.0,>=0.27
15
16
  Requires-Dist: mcp[cli]<2.0,>=1.30
16
17
  Requires-Dist: pyaml<27.0,>=24.0
@@ -25,7 +26,9 @@ Description-Content-Type: text/markdown
25
26
  <!-- mcp-name: io.github.vmware-skills/vmware-aiops -->
26
27
  # VMware AIops
27
28
 
28
- > **Author**: Wei Zhou, VMware by Broadcom — wei-wz.zhou@broadcom.com
29
+ For a read-only check of this skill with your model and agent host, use the shared [model-fit self-test](https://github.com/vmware-skills/marketplace/blob/main/MODEL_FIT_SELF_TEST.md) in the marketplace root.
30
+
31
+ > **Author**: Wei Zhou, VMware by Broadcom — zhouwei008@gmail.com
29
32
  > This is a community-driven project by a VMware engineer, not an official VMware product.
30
33
  > For official VMware developer tools see [developer.broadcom.com](https://developer.broadcom.com).
31
34
 
@@ -33,6 +36,8 @@ English | [中文](README-CN.md)
33
36
 
34
37
  AI-powered VMware vCenter/ESXi VM lifecycle and deployment tool — 61 tools.
35
38
 
39
+ Scope also includes datastore file browsing and deployment image discovery, alarm acknowledgment and reset, and an explicitly started scanning/TTL daemon with optional configured webhooks. Alarm reset can clear multiple matching alarms; guest commands and file transfers retain the account and file-access boundaries documented in the [capabilities reference](skills/vmware-aiops/references/capabilities.md).
40
+
36
41
  > **Companion skills** handle everything else:
37
42
  >
38
43
  > | Skill | Scope | Install |
@@ -365,7 +370,7 @@ Plans stored in `~/.vmware-aiops/plans/`, auto-deleted on success, auto-cleaned
365
370
  | **Password Protection** | `.env` file loading with permission check; never in shell history |
366
371
  | **SSL Self-signed Support** | `verify_ssl: false` — only for ESXi with self-signed certs in isolated labs; production should use CA-signed certificates |
367
372
  | **Prompt Injection Protection** | vSphere event messages and host logs are truncated, stripped of control characters, and wrapped in boundary markers before output |
368
- | **Webhook Data Scope** | Disabled by default. When configured, the daemon posts to your URL only: every critical issue (alarms, events, ESXi log lines matching critical/panic/corrupt, targets it could not connect to) and every alarm/event warning — host-log warnings stay in the scan log, and `info` rows are never sent. Each issue carries its entity name and message: sanitized alarm, event, or ESXi log text, or the connection error, which can include host names, IP addresses, and user names. No credentials from the skill's config or `.env` are sent |
373
+ | **Webhook Data Scope** | Disabled by default. When configured, the daemon posts to your URL only: every critical issue (alarms, events, ESXi log lines matching critical/panic/corrupt, targets it could not connect to) and every alarm/event warning — host-log warnings stay in the scan log, and `info` rows are never sent. Each issue carries its entity name and message: sanitized alarm, event, or ESXi log text, or a generic connection failure class; operational text can include host names, IP addresses, and user names. No credentials from the skill's config or `.env` are sent |
369
374
  | **Task Waiting** | All async operations wait for completion and report result |
370
375
  | **State Validation** | Pre-operation checks (VM exists, power state correct) |
371
376
 
@@ -571,6 +576,8 @@ VMWARE_{TARGET_NAME_UPPER}_PASSWORD
571
576
 
572
577
  ### Security Best Practices
573
578
 
579
+ Scanner notification failures report an HTTP status or exception class. Raw webhook response bodies, transport errors and connection exceptions are excluded from notification diagnostics and audit summaries to keep endpoint tokens out of them.
580
+
574
581
  - **NEVER** hardcode passwords in scripts or config files
575
582
  - **NEVER** pass passwords as command-line arguments (visible in `ps`)
576
583
  - **ALWAYS** use `~/.vmware-aiops/.env` with `chmod 600`
@@ -1,7 +1,9 @@
1
1
  <!-- mcp-name: io.github.vmware-skills/vmware-aiops -->
2
2
  # VMware AIops
3
3
 
4
- > **作者**: Wei Zhou, VMware by Broadcom — wei-wz.zhou@broadcom.com
4
+ 要用自己的模型和 Agent 平台进行只读自测,请看 marketplace 根目录的[共享模型适配自测任务](https://github.com/vmware-skills/marketplace/blob/main/MODEL_FIT_SELF_TEST.md)。
5
+
6
+ > **作者**: Wei Zhou, VMware by Broadcom — zhouwei008@gmail.com
5
7
  > 本项目由 VMware 工程师维护的社区项目,非 VMware 官方产品。
6
8
  > VMware 官方开发者工具请访问 [developer.broadcom.com](https://developer.broadcom.com)。
7
9
 
@@ -9,6 +11,8 @@
9
11
 
10
12
  AI 驱动的 VMware vCenter/ESXi VM 生命周期管理与部署工具 — 61 个工具。
11
13
 
14
+ 范围还包括数据存储文件浏览与部署镜像发现、告警确认与重置,以及需显式启动的扫描/TTL daemon(可选配置 webhook)。告警重置可能清除多个匹配告警;guest 命令与文件传输仍受[能力参考](skills/vmware-aiops/references/capabilities.md)所述的账户和文件访问边界约束。
15
+
12
16
  > **配套技能**负责其他领域:
13
17
  >
14
18
  > | 技能 | 范围 | 安装 |
@@ -287,6 +291,8 @@ Plan 存储在 `~/.vmware-aiops/plans/`,成功后自动删除,超过 24 小
287
291
 
288
292
  ## 安全特性
289
293
 
294
+ 扫描通知失败只报告 HTTP 状态或异常类型。通知诊断与审计摘要不引用原始 webhook 响应、传输错误或连接异常,避免写入其中可能包含的端点令牌。
295
+
290
296
  | 功能 | 说明 |
291
297
  |------|------|
292
298
  | 预演模式(Dry-Run,**仅 CLI**) | 加 `--dry-run` 只打印将要发出的 API 调用而不执行;除 `deploy iso`、`deploy mark-template`、`vm cancel-ttl`、`vm guest-download` 外,每个 CLI 写操作都支持 |
@@ -300,7 +306,7 @@ Plan 存储在 `~/.vmware-aiops/plans/`,成功后自动删除,超过 24 小
300
306
  | 配置文件内容 | `config.yaml` 仅存储主机名、端口和 `.env` 引用路径,**不含密码或 Token** |
301
307
  | SSL 自签名 | 仅用于 ESXi 自签名证书的隔离实验环境;生产环境应使用 CA 签名证书 |
302
308
  | Prompt 注入防护 | vSphere 事件消息和主机日志在输出前进行截断、控制字符清理和边界标记包裹 |
303
- | Webhook 数据范围 | **默认禁用**。配置后,daemon 只向你配置的 URL 发送:所有 critical 问题(告警、事件、匹配 critical/panic/corrupt 的 ESXi 日志行、连不上的目标)和所有告警/事件类 warning——主机日志的 warning 只写入扫描日志,`info` 记录从不发送。每条问题带实体名和消息:经过清洗的告警、事件或 ESXi 日志文本,或连接错误信息,其中可能含主机名、IP 地址和用户名。不会发送 skill 配置或 `.env` 里的任何凭据 |
309
+ | Webhook 数据范围 | **默认禁用**。配置后,daemon 只向你配置的 URL 发送:所有 critical 问题(告警、事件、匹配 critical/panic/corrupt 的 ESXi 日志行、连不上的目标)和所有告警/事件类 warning——主机日志的 warning 只写入扫描日志,`info` 记录从不发送。每条问题带实体名和消息:经过清洗的告警、事件或 ESXi 日志文本,或不含原始异常的连接失败类型;运维文本可能含主机名、IP 地址和用户名。不会发送 skill 配置或 `.env` 里的任何凭据 |
304
310
  | 最小权限 | 推荐使用专用 vCenter 服务账户,仅授予所需最小权限。仅需监控时使用 [VMware-Monitor](https://github.com/vmware-skills/VMware-Monitor) |
305
311
  | 任务等待 | 所有异步操作等待完成并报告结果 |
306
312
 
@@ -1,7 +1,9 @@
1
1
  <!-- mcp-name: io.github.vmware-skills/vmware-aiops -->
2
2
  # VMware AIops
3
3
 
4
- > **Author**: Wei Zhou, VMware by Broadcom — wei-wz.zhou@broadcom.com
4
+ For a read-only check of this skill with your model and agent host, use the shared [model-fit self-test](https://github.com/vmware-skills/marketplace/blob/main/MODEL_FIT_SELF_TEST.md) in the marketplace root.
5
+
6
+ > **Author**: Wei Zhou, VMware by Broadcom — zhouwei008@gmail.com
5
7
  > This is a community-driven project by a VMware engineer, not an official VMware product.
6
8
  > For official VMware developer tools see [developer.broadcom.com](https://developer.broadcom.com).
7
9
 
@@ -9,6 +11,8 @@ English | [中文](README-CN.md)
9
11
 
10
12
  AI-powered VMware vCenter/ESXi VM lifecycle and deployment tool — 61 tools.
11
13
 
14
+ Scope also includes datastore file browsing and deployment image discovery, alarm acknowledgment and reset, and an explicitly started scanning/TTL daemon with optional configured webhooks. Alarm reset can clear multiple matching alarms; guest commands and file transfers retain the account and file-access boundaries documented in the [capabilities reference](skills/vmware-aiops/references/capabilities.md).
15
+
12
16
  > **Companion skills** handle everything else:
13
17
  >
14
18
  > | Skill | Scope | Install |
@@ -341,7 +345,7 @@ Plans stored in `~/.vmware-aiops/plans/`, auto-deleted on success, auto-cleaned
341
345
  | **Password Protection** | `.env` file loading with permission check; never in shell history |
342
346
  | **SSL Self-signed Support** | `verify_ssl: false` — only for ESXi with self-signed certs in isolated labs; production should use CA-signed certificates |
343
347
  | **Prompt Injection Protection** | vSphere event messages and host logs are truncated, stripped of control characters, and wrapped in boundary markers before output |
344
- | **Webhook Data Scope** | Disabled by default. When configured, the daemon posts to your URL only: every critical issue (alarms, events, ESXi log lines matching critical/panic/corrupt, targets it could not connect to) and every alarm/event warning — host-log warnings stay in the scan log, and `info` rows are never sent. Each issue carries its entity name and message: sanitized alarm, event, or ESXi log text, or the connection error, which can include host names, IP addresses, and user names. No credentials from the skill's config or `.env` are sent |
348
+ | **Webhook Data Scope** | Disabled by default. When configured, the daemon posts to your URL only: every critical issue (alarms, events, ESXi log lines matching critical/panic/corrupt, targets it could not connect to) and every alarm/event warning — host-log warnings stay in the scan log, and `info` rows are never sent. Each issue carries its entity name and message: sanitized alarm, event, or ESXi log text, or a generic connection failure class; operational text can include host names, IP addresses, and user names. No credentials from the skill's config or `.env` are sent |
345
349
  | **Task Waiting** | All async operations wait for completion and report result |
346
350
  | **State Validation** | Pre-operation checks (VM exists, power state correct) |
347
351
 
@@ -547,6 +551,8 @@ VMWARE_{TARGET_NAME_UPPER}_PASSWORD
547
551
 
548
552
  ### Security Best Practices
549
553
 
554
+ Scanner notification failures report an HTTP status or exception class. Raw webhook response bodies, transport errors and connection exceptions are excluded from notification diagnostics and audit summaries to keep endpoint tokens out of them.
555
+
550
556
  - **NEVER** hardcode passwords in scripts or config files
551
557
  - **NEVER** pass passwords as command-line arguments (visible in `ps`)
552
558
  - **ALWAYS** use `~/.vmware-aiops/.env` with `chmod 600`
@@ -1,3 +1,21 @@
1
+ ## v2.4.4 — minimize notification and audit secrets (2026-11-08)
2
+
3
+ * Update public author/project contact metadata to `zhouwei008@gmail.com`.
4
+
5
+ ### notification secret minimization
6
+ * Webhook status/transport logs and unexpected scan/send audit failures retain HTTP status or exception class without raw response/exception text. Connection-failure notifications no longer forward raw exceptions that can contain credential-bearing URLs or opaque tokens.
7
+
8
+ ### scope declaration
9
+ * Explicitly declare the existing datastore browsing/image discovery, multi-alarm reset and user-started scanning/TTL daemon capabilities in the canonical skill description and both READMEs. Runtime behavior, permission boundaries and risk disclosures are unchanged.
10
+
11
+ ## v2.4.3 — bind confirmed writes to measured identities; reject ambiguous inventory names (2026-11-08)
12
+
13
+ * **Confirmed MCP writes re-check the identities measured during that call.** The eight confirm-gated VM and snapshot tools pass the current blast-radius measurement's VM instance UUID and snapshot id into execution, refusing a replacement object found by the executor. Each `confirm=True` invocation measures afresh; the separate earlier preview supplies no identity token. The existing `delete_vm` acknowledgement requirement is unchanged, as are the CLI and plan-executor paths (AIops#49).
14
+ * **Missing objects in delegated investigation tools keep their remedy.** VM, host and datastore lookup errors from vmware-monitor retain the exact-name/listing guidance through AIops MCP and are classified as request errors; unexpected delegate failures remain reduced to their type.
15
+ * **Ambiguous host, cluster, datastore and datacenter names are refused.** A lookup that finds more than one match raises `AmbiguousNameError` with the matching managed-object ids; plan prechecks and CLI output expose the ambiguity instead of selecting the first result (AIops#48).
16
+ * The image-cache and TTL cross-process file lock is exercised on a real Windows GitHub Actions runner: four concurrent writers retain every row, a held lock times out with the lock path, and the lock is released after the holder exits (AIops#51).
17
+ * Require certifi 2026.10.19 or later to exclude the compromised emSign root CA from the TLS trust bundle (GHSA-6q48-6c7w-9gw2). The development lock resolves 2026.10.23 (AIops#53).
18
+
1
19
  ## v2.4.2 — a login refused for lack of a role says so; an unreadable host is not called unreachable (2026-10-19)
2
20
 
3
21
  Needs vmware-monitor 2.4.2 (now the floor). Found on a vCenter 8.0.3 lab with two restricted SSO accounts
@@ -1944,7 +1962,7 @@ This release tracks vmware-pilot v1.5.17 (new `investigate_alert` template + `re
1944
1962
  - **[READ]/[WRITE] tool prefixes**: All MCP tool descriptions now start with [READ] or [WRITE] to clearly indicate operation type
1945
1963
  - **Read/write split counts**: SKILL.md MCP Tools section header shows exact read vs write tool counts
1946
1964
  - **Negative routing**: Description frontmatter includes "Do NOT use when..." clause to prevent misrouting
1947
- - **Broadcom author attestation**: README.md, README-CN.md, and pyproject.toml include VMware by Broadcom author identity (wei-wz.zhou@broadcom.com) to resolve Snyk E005 brand warnings
1965
+ - **Broadcom author attestation**: README.md, README-CN.md, and pyproject.toml include VMware by Broadcom author identity (zhouwei008@gmail.com) to resolve Snyk E005 brand warnings
1948
1966
 
1949
1967
  ### AIops-specific
1950
1968
 
@@ -2642,4 +2660,4 @@ vmware-aiops vks clusters|health|scale|nodes
2642
2660
  多目标配置。
2643
2661
 
2644
2662
  - Environment variable password management.
2645
- 环境变量密码管理。
2663
+ 环境变量密码管理。
@@ -4,13 +4,13 @@
4
4
 
5
5
  This is a community-maintained open-source project and is **not affiliated with, endorsed by, or sponsored by VMware, Inc. or Broadcom Inc.** "VMware" and "vSphere" are trademarks of Broadcom Inc.
6
6
 
7
- **Author**: Wei Zhou, VMware by Broadcom — wei-wz.zhou@broadcom.com
7
+ **Author**: Wei Zhou, VMware by Broadcom — zhouwei008@gmail.com
8
8
 
9
9
  ## Reporting Vulnerabilities
10
10
 
11
11
  If you discover a security vulnerability, please report it privately:
12
12
 
13
- - **Email**: wei-wz.zhou@broadcom.com
13
+ - **Email**: zhouwei008@gmail.com
14
14
  - **GitHub**: Open a [private security advisory](https://github.com/vmware-skills/VMware-AIops/security/advisories/new)
15
15
 
16
16
  Do **not** open a public GitHub issue for security vulnerabilities.
@@ -11,7 +11,7 @@
11
11
  "command": "uvx",
12
12
  "args": [
13
13
  "--from",
14
- "vmware-aiops==2.4.2",
14
+ "vmware-aiops==2.4.4",
15
15
  "vmware-aiops-mcp"
16
16
  ]
17
17
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zw008/vmware-aiops",
3
- "version": "2.4.2",
3
+ "version": "2.4.4",
4
4
  "description": "AI-powered VMware vCenter/ESXi VM lifecycle and deployment with 61 MCP tools.",
5
5
  "private": true,
6
6
  "license": "MIT",
@@ -4,12 +4,12 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "vmware-aiops"
7
- version = "2.4.2"
7
+ version = "2.4.4"
8
8
  description = "VMware vCenter/ESXi AI-powered VM lifecycle and deployment tool"
9
9
  readme = "README.md"
10
10
  license = "MIT"
11
11
  requires-python = ">=3.10"
12
- authors = [{ name = "Wei Zhou", email = "wei-wz.zhou@broadcom.com" }]
12
+ authors = [{ name = "Wei Zhou", email = "zhouwei008@gmail.com" }]
13
13
  dependencies = [
14
14
  "pyvmomi>=8.0.3.0,<10.0",
15
15
  "pyaml>=24.0,<27.0",
@@ -17,6 +17,7 @@ dependencies = [
17
17
  "rich>=13.0,<16.0",
18
18
  "apscheduler>=3.10,<4.0",
19
19
  "httpx>=0.27,<1.0",
20
+ "certifi>=2026.10.19", # GHSA-6q48-6c7w-9gw2: exclude compromised emSign root
20
21
  "python-dotenv>=1.0,<2.0",
21
22
  "mcp[cli]>=1.30,<2.0",
22
23
  "vmware-policy>=1.23.1,<2.0",
@@ -7,12 +7,12 @@
7
7
  "url": "https://github.com/vmware-skills/VMware-AIops",
8
8
  "source": "github"
9
9
  },
10
- "version": "2.4.2",
10
+ "version": "2.4.4",
11
11
  "packages": [
12
12
  {
13
13
  "registryType": "pypi",
14
14
  "identifier": "vmware-aiops",
15
- "version": "2.4.2",
15
+ "version": "2.4.4",
16
16
  "runtimeHint": "uvx",
17
17
  "packageArguments": [
18
18
  {
@@ -1,11 +1,15 @@
1
1
  ---
2
2
  name: vmware-aiops
3
3
  description: >
4
- Use this skill whenever the user needs to manage VMs in VMware/vSphere/ESXi — it's the entry point for all VM operations.
5
- Directly handles: power on/off, clone, snapshot, migrate, deploy from OVA or templates, run commands inside VMs, batch operations, cluster management, vCenter alarm acknowledgment, a one-glance cluster-health triage ("is anything on fire?"), and VM/host/datastore investigation drill-downs.
6
- Always use this skill for any "power on", "clone", "deploy", "migrate", "batch", "guest exec", "alarm", or VM lifecycle task, and for triage like "is anything on fire" / "what needs attention now" / "investigate this VM", when the context is explicitly VMware, vSphere, or ESXi.
7
- Do NOT use for general read-only queries (inventory/events/VM details — use vmware-monitor), NSX networking (use vmware-nsx), storage/iSCSI/vSAN (use vmware-storage), or Kubernetes cluster lifecycle (use vmware-vks).
8
- For multi-step workflows use vmware-pilot. For load balancing/AVI/AKO use vmware-avi.
4
+ Use for VMware/vSphere/ESXi VM lifecycle: power on/off, clone, snapshot, migrate,
5
+ OVA/template deployment, guest commands and file transfer, batch operations, plans and clusters.
6
+ Also handles datastore file browsing and deployment image scanning; alarm acknowledgment
7
+ and reset (which can clear multiple matching alarms); read-only cluster/VM/host/datastore
8
+ triage; and a user-started scanning/TTL daemon with optional configured webhooks.
9
+ Always use for power on, clone, deploy, migrate, guest exec, batch, alarms or VM investigation
10
+ in VMware. Use vmware-monitor for general read-only inventory/events/VM details;
11
+ vmware-storage for iSCSI/vSAN/storage configuration; vmware-nsx for NSX;
12
+ vmware-vks for Kubernetes; vmware-pilot for workflows; vmware-avi for load balancing.
9
13
  installer:
10
14
  kind: uv
11
15
  package: vmware-aiops
@@ -25,6 +29,8 @@ compatibility: >
25
29
 
26
30
  # VMware AIops
27
31
 
32
+ > Self-test: [guide](https://github.com/vmware-skills/marketplace/blob/main/MODEL_FIT_SELF_TEST.md).
33
+
28
34
  > **Disclaimer**: This is a community-maintained open-source project and is **not affiliated with, endorsed by, or sponsored by VMware, Inc. or Broadcom Inc.** "VMware" and "vSphere" are trademarks of Broadcom. Source code is publicly auditable at [github.com/vmware-skills/VMware-AIops](https://github.com/vmware-skills/VMware-AIops) under the MIT license.
29
35
 
30
36
  VMware family entry point — AI-powered VM lifecycle, deployment, and alarm management — 61 MCP tools.
@@ -63,7 +69,7 @@ Read before connecting an agent. Per-tool inventory: `references/capabilities.md
63
69
  ## Quick Install
64
70
 
65
71
  ```bash
66
- uv tool install vmware-aiops==2.4.2
72
+ uv tool install vmware-aiops==2.4.4
67
73
  vmware-aiops doctor
68
74
  vmware-aiops hub status # see which family members are installed
69
75
  ```
@@ -303,7 +309,7 @@ The account has no vSphere role. Assign one (Read-Only or higher) on the vCenter
303
309
  ## Setup
304
310
 
305
311
  ```bash
306
- uv tool install vmware-aiops==2.4.2
312
+ uv tool install vmware-aiops==2.4.4
307
313
  mkdir -p ~/.vmware-aiops
308
314
  vmware-aiops init # generates config.yaml and .env templates
309
315
  chmod 600 ~/.vmware-aiops/.env
@@ -59,6 +59,8 @@ well-meaning agents, not a replacement for RBAC.
59
59
  - **Cluster** (`delete_cluster`, `remove_cluster_host`): member hosts, VMs, datastores. Refused while hosts or VMs are still in the cluster, or when the host is not in maintenance mode or still runs powered-on VMs.
60
60
  - **Clean Slate / TTL** (`restore_vm_clean_slate`, `set_vm_ttl`): the snapshot and what the revert discards; for a TTL, the VM that will be deleted unattended and when. Clean Slate is refused when the baseline snapshot is missing or its name is ambiguous — before anything is powered off — and reports an error, not `reverted`, if the revert did not happen. The TTL entry records the VM's target and instance UUID; at expiry the daemon deletes only a VM that still has that UUID (another VM under the same name is left alone, the entry dropped and the refusal audited). A TTL is refused on every `delete_vm` blocker except the power state (the daemon powers off first).
61
61
  - **Snapshot names** (`revert_vm_snapshot`, `delete_vm_snapshot`, `restore_vm_clean_slate`): a name matches a snapshot's raw name or the name `list_vm_snapshots` shows (control/invisible characters stripped). Two snapshots matching the same name — duplicates, or names that differ only by stripped characters — are refused by the gate and by the executors, which no longer take the first.
62
+ - **Object names**: looking up a VM, host, cluster, datastore or datacenter by name across the vCenter refuses a name that matches more than one object of that kind, and lists the matches' managed-object ids, instead of taking the first. Cluster and datastore names are unique only within a datacenter, so two datacenters can each have a `Cluster01`.
63
+ - **What a confirmed call acts on** (`power_off_vm`, `migrate_vm`, `revert_vm_snapshot`, `delete_vm_snapshot`, `run_vm_guest_command`, `run_vm_guest_command_with_output`, `upload_vm_guest_file`, `provision_vm_guest`): the VM measured within that invocation, checked by instance UUID, and for snapshots the snapshot measured then, checked by id. Replacement between that measurement and the executor's lookup is refused ("not the VM that was previewed") before it changes anything. Each `confirm=True` invocation measures afresh; an earlier separate preview supplies no identity token. The `delete_vm` acknowledgement below remains the explicit check against a prior preview.
62
64
  - **Plans** (`apply_vm_plan`, `rollback_vm_plan`): every step with its full parameters (passwords and other secret-looking keys redacted), which are destructive and which cannot be rolled back. Each destructive step is measured as its own tool measures it, and that tool's `blockers` / `unmeasured` become the plan's, prefixed `Step N (action):`. A step on an object an earlier step creates or changes (power off, then delete; a VM a step creates) is shown `check: "deferred"` and measured immediately before it runs; every destructive step is re-checked then, and a failed check stops the plan with a teaching error in that step's result. Refused when `target` does not match the plan's (no target is a target of its own), a step would be refused by its tool, or a plan step with action delete_vm carries no `acknowledge_blast_radius`. Every action the executor can run is classified: measured by its tool's gate (including `migrate`, measured as `migrate_vm`), refused, or non-destructive with a stated reason; anything else is refused rather than run unchecked. The plan actions `iscsi_enable`, `iscsi_add_target`, `iscsi_remove_target` and `storage_rescan` (plan-file action names, not tools) are gated in vmware-storage and cannot be measured here, so a plan containing one is refused at preview, apply and rollback — use `enable_iscsi`, `add_iscsi_target`, `remove_iscsi_target` / `rescan_storage` instead. Rollback steps get the same checks: each destructive rollback step (power off, delete snapshot, cluster delete, host removal) is measured in the `rollback_vm_plan` preview and again just before it runs; a refused check stops the rollback with a teaching error for that step, and the plan stays `failed` so rollback can be run again. A step that creates a VM records its instance UUID; rollback deletes the VM only if it still has that UUID, and refuses that rollback step otherwise. Plan responses never echo step passwords; secret keys are matched as whole name tokens (`password`, `passwd`, `pwd`, `secret`, `token`, `api_key`, `auth`, `credential(s)`, `private_key`).
63
65
  - **Refusal messages** lead with the first blocker (problem and remedy) and count the rest ("…and 2 more blockers"), and stay within 480 characters; the preview lists every blocker.
64
66
  - **Network / DRS** (`add_host_vmk`, `remove_host_vmk`, `set_vmk_service`, `create_dvs_portgroup`, `create_drs_rule`, `delete_drs_rule`, `set_drs_rule_enabled`): what would be created, changed or removed, with `blockers` and `unmeasured`; `remove_host_vmk` and `set_vmk_service` fail closed on an unreadable service map. Their refusals (a protected or the only management vmk, a VM-Host DRS rule) are reported as blockers in the preview and still raise on `confirm=True`.
@@ -6,13 +6,13 @@ All install methods fetch from the same source: [github.com/vmware-skills/VMware
6
6
 
7
7
  ```bash
8
8
  # Via PyPI (recommended for version pinning)
9
- uv tool install vmware-aiops==2.4.2
9
+ uv tool install vmware-aiops==2.4.4
10
10
 
11
11
  # Via Skills.sh (fetches from GitHub)
12
- npx skills add vmware-skills/VMware-AIops#v2.4.2
12
+ npx skills add vmware-skills/VMware-AIops#v2.4.4
13
13
 
14
14
  # Via ClawHub (fetches from ClawHub registry snapshot of GitHub)
15
- clawhub install @zw008/vmware-aiops --version 2.4.2
15
+ clawhub install @zw008/vmware-aiops --version 2.4.4
16
16
  ```
17
17
 
18
18
  ### Claude Code
@@ -35,7 +35,7 @@ claude mcp add vmware-aiops -- vmware-aiops mcp
35
35
 
36
36
  ```bash
37
37
  # 1. Install from PyPI (source: github.com/vmware-skills/VMware-AIops)
38
- uv tool install vmware-aiops==2.4.2
38
+ uv tool install vmware-aiops==2.4.4
39
39
 
40
40
  # 2. Verify installation source
41
41
  vmware-aiops --version # confirms installed version
@@ -73,7 +73,7 @@ The `vmware-aiops` package installs a Python CLI binary and its dependencies (py
73
73
  ## Development Install
74
74
 
75
75
  ```bash
76
- git clone --branch v2.4.2 https://github.com/vmware-skills/VMware-AIops.git
76
+ git clone --branch v2.4.4 https://github.com/vmware-skills/VMware-AIops.git
77
77
  cd VMware-AIops
78
78
  uv venv && source .venv/bin/activate
79
79
  # --no-sources: pyproject's [tool.uv.sources] points vmware-monitor at a sibling
@@ -0,0 +1,70 @@
1
+ """Monitor's missing-object remedies must survive the AIops MCP error wrapper.
2
+
3
+ Found on real vCenter, 2026-11-08: investigate_vm reduced Monitor's authored
4
+ VMNotFoundError to a generic failure and incorrectly suggested checking login.
5
+ The host and datastore delegates use different authored exception classes too.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import asyncio
10
+ import importlib
11
+ import json
12
+
13
+ import mcp.types as mcp_types
14
+ import pytest
15
+ from vmware_policy.policy import reset_policy_engine
16
+
17
+ from vmware_aiops.mcp_server.server import mcp
18
+ from vmware_aiops.mcp_server.tools import summary
19
+
20
+
21
+ @pytest.fixture(autouse=True)
22
+ def policy_home(tmp_path, monkeypatch):
23
+ monkeypatch.setenv("OPS_HOME", str(tmp_path))
24
+ reset_policy_engine()
25
+ yield
26
+ reset_policy_engine()
27
+
28
+
29
+ def call(tool, arguments):
30
+ handler = mcp._mcp_server.request_handlers[mcp_types.CallToolRequest]
31
+ request = mcp_types.CallToolRequest(
32
+ method="tools/call",
33
+ params=mcp_types.CallToolRequestParams(name=tool, arguments=arguments),
34
+ )
35
+ result = asyncio.run(handler(request)).root
36
+ text = "".join(b.text for b in result.content if isinstance(b, mcp_types.TextContent))
37
+ return result, json.loads(text)
38
+
39
+
40
+ @pytest.mark.parametrize(("kind", "lookup", "listing"), [
41
+ ("vm", "find_vm_by_name", "list_virtual_machines"),
42
+ ("host", "find_host_by_name", "list_esxi_hosts"),
43
+ ("datastore", "find_datastore_by_name", "list_all_datastores"),
44
+ ])
45
+ def test_missing_delegate_object_keeps_its_real_remedy(monkeypatch, kind, lookup, listing):
46
+ # Exercise the real Monitor raise site, not a reconstructed exception.
47
+ module = importlib.import_module(f"vmware_monitor.ops.investigate_{kind}")
48
+ monkeypatch.setattr(module, lookup, lambda *_args: None)
49
+ monkeypatch.setattr(summary, "_get_connection", lambda *_args: object())
50
+ result, payload = call(f"investigate_{kind}", {f"{kind}_name": "missing-\x00object"})
51
+ assert result.isError is True
52
+ assert "not found" in payload["error"]
53
+ assert listing in payload["error"]
54
+ assert "missing-object" in payload["error"]
55
+ assert "\x00" not in payload["error"]
56
+ assert "doctor" not in payload["hint"]
57
+
58
+
59
+ @pytest.mark.parametrize("error_type", [RuntimeError, type("VMNotFoundError", (Exception,), {})])
60
+ def test_unplanned_delegate_errors_are_still_reduced(monkeypatch, error_type):
61
+ def fail(*_args, **_kwargs):
62
+ raise error_type("https://svc:secret-example@internal.invalid/api")
63
+
64
+ monkeypatch.setattr(summary, "_get_connection", lambda *_args: object())
65
+ monkeypatch.setattr(summary, "get_vm_investigation_bundle", fail)
66
+ result, payload = call("investigate_vm", {"vm_name": "missing-object"})
67
+ assert result.isError is True
68
+ assert payload["error"] == f"{error_type.__name__}: operation failed."
69
+ assert "secret-example" not in str(payload)
70
+ assert "doctor" in payload["hint"]
@@ -226,7 +226,7 @@ def test_falsy_error_key_is_not_a_failure(monkeypatch) -> None:
226
226
  # stubbed clean so this stays about the falsy error key.
227
227
  monkeypatch.setattr(
228
228
  "vmware_aiops.mcp_server.tools.guest.measure_guest_provision",
229
- lambda *a, **k: {"blockers": [], "unmeasured": []},
229
+ lambda *a, **k: {"instance_uuid": "uuid-1", "blockers": [], "unmeasured": []},
230
230
  )
231
231
 
232
232
  result = call(
@@ -89,7 +89,7 @@ def test_a_cpu_feature_refusal_leads_with_the_remedy(monkeypatch) -> None:
89
89
  vm.datastore = []
90
90
  host = MagicMock()
91
91
  host.parent.resourcePool = vim.ResourcePool("resgroup-1", None)
92
- monkeypatch.setattr(vm_lifecycle, "_require_vm", lambda si, n: vm)
92
+ monkeypatch.setattr(vm_lifecycle, "_require_vm", lambda si, n, **k: vm)
93
93
  monkeypatch.setattr(vm_lifecycle, "find_host_by_name", lambda si, n: host)
94
94
  monkeypatch.setattr(vm_lifecycle.vim.vm, "RelocateSpec", lambda **k: MagicMock())
95
95
 
@@ -0,0 +1,127 @@
1
+ """Host, cluster, datastore and datacenter lookups refuse a duplicated name.
2
+
3
+ VMs already do (``AmbiguousVMError``, 2026-09-16). The other finders still
4
+ returned whichever object the property collector listed first. Cluster and
5
+ datastore names are unique only within a datacenter, so on a vCenter with two
6
+ datacenters ``add_cluster_host("Cluster01", …)`` could move a host into the
7
+ other datacenter's cluster, and the result reads exactly like a success.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from unittest.mock import MagicMock
13
+
14
+ import pytest
15
+ from pyVmomi import vim
16
+ from vmware_policy.budget import reset_budget
17
+ from vmware_policy.policy import reset_policy_engine
18
+ from vmware_policy.undo import reset_undo_store
19
+
20
+ import vmware_aiops.mcp_server.tools.cluster as cluster_tools
21
+ from vmware_aiops.ops import inventory
22
+ from vmware_aiops.ops.inventory import AmbiguousNameError, AmbiguousVMError, InventoryError
23
+
24
+
25
+ @pytest.fixture(autouse=True)
26
+ def harness(tmp_path, monkeypatch):
27
+ monkeypatch.setenv("OPS_HOME", str(tmp_path))
28
+ reset_policy_engine()
29
+ reset_budget()
30
+ reset_undo_store()
31
+ yield
32
+ reset_policy_engine()
33
+ reset_budget()
34
+ reset_undo_store()
35
+
36
+
37
+ def _obj(name: str, moid: str) -> MagicMock:
38
+ obj = MagicMock(name=f"obj:{name}:{moid}")
39
+ obj.name = name
40
+ obj._moId = moid
41
+ return obj
42
+
43
+
44
+ @pytest.fixture
45
+ def inventory_of(monkeypatch):
46
+ """Serve ``_collect`` per managed-object type from a fixed inventory."""
47
+ def install(by_type: dict):
48
+ monkeypatch.setattr(
49
+ inventory, "_collect",
50
+ lambda _si, types, _props: [(o, {"name": o.name}) for o in by_type.get(types[0], [])],
51
+ )
52
+ return by_type
53
+ return install
54
+
55
+
56
+ FINDERS = [
57
+ (inventory.find_host_by_name, vim.HostSystem, "host"),
58
+ (inventory.find_cluster_by_name, vim.ClusterComputeResource, "cluster"),
59
+ (inventory.find_datastore_by_name, vim.Datastore, "datastore"),
60
+ (inventory.find_datacenter_by_name, vim.Datacenter, "datacenter"),
61
+ ]
62
+
63
+
64
+ @pytest.mark.parametrize(("finder", "kind", "label"), FINDERS)
65
+ def test_a_duplicated_name_is_refused_and_names_both_objects(inventory_of, finder, kind, label):
66
+ inventory_of({kind: [_obj("X", "obj-1"), _obj("X", "obj-2"), _obj("Y", "obj-3")]})
67
+
68
+ with pytest.raises(AmbiguousNameError) as raised:
69
+ finder(MagicMock(), "X")
70
+
71
+ message = str(raised.value)
72
+ assert f"2 {label}s are named 'X'" in message
73
+ assert "obj-1" in message and "obj-2" in message
74
+
75
+
76
+ @pytest.mark.parametrize(("finder", "kind", "label"), FINDERS)
77
+ def test_a_unique_name_still_resolves_and_a_missing_one_is_none(inventory_of, finder, kind, label):
78
+ only = _obj("X", "obj-1")
79
+ inventory_of({kind: [only, _obj("Y", "obj-2")]})
80
+
81
+ assert finder(MagicMock(), "X") is only
82
+ assert finder(MagicMock(), "nope") is None
83
+
84
+
85
+ def test_the_vm_error_is_one_kind_of_ambiguous_name():
86
+ # Callers that catch AmbiguousVMError keep working; new ones catch the base.
87
+ assert issubclass(AmbiguousVMError, AmbiguousNameError)
88
+ assert issubclass(AmbiguousNameError, InventoryError)
89
+
90
+
91
+ def test_add_cluster_host_refuses_a_duplicated_cluster_and_moves_nothing(inventory_of, monkeypatch):
92
+ dc1, dc2 = _obj("Cluster01", "domain-c1"), _obj("Cluster01", "domain-c2")
93
+ inventory_of({vim.ClusterComputeResource: [dc1, dc2], vim.HostSystem: [_obj("esx-01", "host-1")]})
94
+ monkeypatch.setattr(cluster_tools, "_get_connection", lambda _t=None: MagicMock())
95
+
96
+ out = cluster_tools.add_cluster_host("Cluster01", "esx-01")
97
+
98
+ assert "2 clusters are named 'Cluster01'" in out
99
+ dc1.MoveInto_Task.assert_not_called()
100
+ dc2.MoveInto_Task.assert_not_called()
101
+
102
+
103
+ def test_a_plan_that_migrates_to_a_duplicated_host_fails_validation_not_the_planner(inventory_of):
104
+ from vmware_aiops.ops.planner import precheck_targets
105
+
106
+ inventory_of({
107
+ vim.VirtualMachine: [_obj("web-01", "vm-1")],
108
+ vim.HostSystem: [_obj("esx-01", "host-1"), _obj("esx-01", "host-2")],
109
+ })
110
+
111
+ errors = precheck_targets(
112
+ MagicMock(), [{"action": "migrate", "vm_name": "web-01", "target_host": "esx-01"}]
113
+ )
114
+
115
+ assert any("2 hosts are named 'esx-01'" in e for e in errors), errors
116
+
117
+
118
+ def test_many_matches_list_a_few_ids_and_count_the_rest(inventory_of):
119
+ inventory_of({vim.Datastore: [_obj("ds", f"datastore-{i}") for i in range(8)]})
120
+
121
+ with pytest.raises(AmbiguousNameError) as raised:
122
+ inventory.find_datastore_by_name(MagicMock(), "ds")
123
+
124
+ message = str(raised.value)
125
+ assert "8 datastores are named 'ds'" in message
126
+ assert "datastore-4" in message and "datastore-5" not in message
127
+ assert "and 3 more" in message