cli-dolibarr 3.32.2__tar.gz → 3.32.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 (179) hide show
  1. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/PKG-INFO +1 -1
  2. cli_dolibarr-3.32.4/cli_dolibarr/dolibarr/__init__.py +1 -0
  3. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/mcp_server/search_actions.py +17 -5
  4. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/mcp_server/tiering.py +5 -2
  5. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_mcp_search_actions.py +25 -0
  6. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_mcp_tiering.py +16 -1
  7. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr.egg-info/PKG-INFO +1 -1
  8. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr.egg-info/SOURCES.txt +0 -2
  9. cli_dolibarr-3.32.2/cli_dolibarr/dolibarr/__init__.py +0 -1
  10. cli_dolibarr-3.32.2/cli_dolibarr/dolibarr/tests/test_mcp_harvest_args.py +0 -84
  11. cli_dolibarr-3.32.2/cli_dolibarr/dolibarr/tests/test_mcp_usage_db.py +0 -76
  12. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/LICENSE +0 -0
  13. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/README.md +0 -0
  14. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/README.md +0 -0
  15. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/__init__.py +0 -0
  16. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/_template.py +0 -0
  17. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/accountancy.py +0 -0
  18. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/agendaevents.py +0 -0
  19. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/apibridge.py +0 -0
  20. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/bankaccounts.py +0 -0
  21. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/boms.py +0 -0
  22. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/categories.py +0 -0
  23. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/config.py +0 -0
  24. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/contacts.py +0 -0
  25. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/contracts.py +0 -0
  26. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/countries.py +0 -0
  27. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/delivery.py +0 -0
  28. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/documents.py +0 -0
  29. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/donations.py +0 -0
  30. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/expensereports.py +0 -0
  31. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/interventions.py +0 -0
  32. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/invoices.py +0 -0
  33. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/knowledge.py +0 -0
  34. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/login.py +0 -0
  35. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/member_types.py +0 -0
  36. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/members.py +0 -0
  37. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/mobilehub.py +0 -0
  38. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/mobilehubapi.py +0 -0
  39. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/mos.py +0 -0
  40. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/mprplus.py +0 -0
  41. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/multicurrencies.py +0 -0
  42. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/orderprocessor.py +0 -0
  43. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/orders.py +0 -0
  44. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/partnerships.py +0 -0
  45. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/pdfa.py +0 -0
  46. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/productplus.py +0 -0
  47. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/products.py +0 -0
  48. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/projects.py +0 -0
  49. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/proposals.py +0 -0
  50. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/quickprint.py +0 -0
  51. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/receptions.py +0 -0
  52. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/recruitments.py +0 -0
  53. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/salaries.py +0 -0
  54. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/schema.py +0 -0
  55. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/setup.py +0 -0
  56. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/shipments.py +0 -0
  57. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/status.py +0 -0
  58. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/stock.py +0 -0
  59. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/stockmodule.py +0 -0
  60. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/stockmovements.py +0 -0
  61. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/subscriptions.py +0 -0
  62. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/supplier_invoices.py +0 -0
  63. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/supplier_orders.py +0 -0
  64. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/supplier_proposals.py +0 -0
  65. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/supplierinvoices.py +0 -0
  66. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/supplierorders.py +0 -0
  67. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/supplierproposals.py +0 -0
  68. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/system.py +0 -0
  69. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/systemapi.py +0 -0
  70. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/tasks.py +0 -0
  71. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/thirdparties.py +0 -0
  72. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/tickets.py +0 -0
  73. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/tools.py +0 -0
  74. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/users.py +0 -0
  75. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/warehouses.py +0 -0
  76. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/webhook.py +0 -0
  77. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/workstations.py +0 -0
  78. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/commands/zapier.py +0 -0
  79. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/core/__init__.py +0 -0
  80. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/core/client.py +0 -0
  81. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/core/config.py +0 -0
  82. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/core/output.py +0 -0
  83. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/core/schema_agents.py +0 -0
  84. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/core/schema_audit.py +0 -0
  85. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/core/schema_generator.py +0 -0
  86. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/core/schema_manager.py +0 -0
  87. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/core/session_client.py +0 -0
  88. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/dolibarr_cli.py +0 -0
  89. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/extrafields_cache.json +0 -0
  90. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/hermes_plugin/__init__.py +0 -0
  91. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/hermes_plugin/install.sh +0 -0
  92. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/hermes_plugin/plugin.yaml +0 -0
  93. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/mcp_server/__init__.py +0 -0
  94. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/mcp_server/__main__.py +0 -0
  95. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/mcp_server/domains.py +0 -0
  96. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/mcp_server/error_guidance.py +0 -0
  97. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/mcp_server/field_hints.py +0 -0
  98. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/mcp_server/param_aliases.py +0 -0
  99. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/mcp_server/projections.py +0 -0
  100. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/mcp_server/registry.py +0 -0
  101. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/mcp_server/sanitizer.py +0 -0
  102. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/mcp_server/server.py +0 -0
  103. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/mcp_server/validators.py +0 -0
  104. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/models_supplement.json +0 -0
  105. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/schema.json +0 -0
  106. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/__init__.py +0 -0
  107. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_audit.py +0 -0
  108. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_boms.py +0 -0
  109. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_cli.py +0 -0
  110. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_contracts.py +0 -0
  111. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_core.py +0 -0
  112. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_dispatch.py +0 -0
  113. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_documents.py +0 -0
  114. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_enrich.py +0 -0
  115. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_executor_error_handling.py +0 -0
  116. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_executor_request_body_unwrap.py +0 -0
  117. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_full_e2e.py +0 -0
  118. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_g4_body_models_probe.py +0 -0
  119. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_hermes_register.py +0 -0
  120. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_invoices.py +0 -0
  121. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_mcp_auth.py +0 -0
  122. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_mcp_error_guidance.py +0 -0
  123. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_mcp_field_hints.py +0 -0
  124. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_mcp_leak_audit.py +0 -0
  125. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_mcp_list_document_id_ref_guidance.py +0 -0
  126. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_mcp_makeorder_date_backfill.py +0 -0
  127. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_mcp_makeorder_nested_data_unwrap.py +0 -0
  128. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_mcp_param_aliases.py +0 -0
  129. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_mcp_registry.py +0 -0
  130. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_mcp_sanitizer.py +0 -0
  131. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_mcp_server.py +0 -0
  132. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_mcp_transport.py +0 -0
  133. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_mobilehubapi_aidoc.py +0 -0
  134. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_mobilehubapi_stockin_queued.py +0 -0
  135. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_mos.py +0 -0
  136. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_mprplus_endpoints.py +0 -0
  137. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_mprplus_mo_deliver.py +0 -0
  138. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_orderprocessor_endpoints.py +0 -0
  139. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_orderprocessor_ocr_jobs.py +0 -0
  140. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_orderprocessor_product_stats.py +0 -0
  141. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_orderprocessor_recon_monthly_period.py +0 -0
  142. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_orderprocessor_reconciliation_fixes.py +0 -0
  143. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_orderprocessor_smartupload.py +0 -0
  144. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_orderprocessor_statement_email.py +0 -0
  145. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_orders.py +0 -0
  146. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_pdfa.py +0 -0
  147. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_productplus.py +0 -0
  148. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_products_purchase_prices_multicurrency.py +0 -0
  149. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_proposals.py +0 -0
  150. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_receptions.py +0 -0
  151. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_schema_generator.py +0 -0
  152. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_setup.py +0 -0
  153. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_setup_dictionary_availability.py +0 -0
  154. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_setup_dictionary_incoterms.py +0 -0
  155. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_supplier_invoices.py +0 -0
  156. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_supplier_orders.py +0 -0
  157. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_supplier_proposals.py +0 -0
  158. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_supplierinvoices.py +0 -0
  159. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_supplierorders.py +0 -0
  160. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_systemapi.py +0 -0
  161. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_thirdparty_fk_warehouse_split.py +0 -0
  162. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_tool_config.py +0 -0
  163. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_tool_filter.py +0 -0
  164. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tests/test_tools.py +0 -0
  165. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tools/__init__.py +0 -0
  166. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tools/executor.py +0 -0
  167. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tools/tool_config.py +0 -0
  168. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tools/tool_translations.json +0 -0
  169. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tools/tool_ui.html +0 -0
  170. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tools/tool_ui.py +0 -0
  171. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/tools/tools_schema.py +0 -0
  172. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/utils/__init__.py +0 -0
  173. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr/dolibarr/utils/multicurrency.py +0 -0
  174. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr.egg-info/dependency_links.txt +0 -0
  175. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr.egg-info/entry_points.txt +0 -0
  176. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr.egg-info/requires.txt +0 -0
  177. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/cli_dolibarr.egg-info/top_level.txt +0 -0
  178. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/pyproject.toml +0 -0
  179. {cli_dolibarr-3.32.2 → cli_dolibarr-3.32.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cli-dolibarr
3
- Version: 3.32.2
3
+ Version: 3.32.4
4
4
  Summary: CLI tool for Dolibarr ERP/CRM REST API management
5
5
  Author: CLI Anything
6
6
  License-Expression: MIT
@@ -0,0 +1 @@
1
+ __version__ = "3.32.4"
@@ -8,20 +8,29 @@ from __future__ import annotations
8
8
  import json
9
9
  from typing import Any, Dict, Optional
10
10
 
11
+ from . import tiering as _tiering
12
+
11
13
  SEARCH_ACTIONS_NAME = "search_actions"
12
14
  HOST_DOMAIN = "erp_system"
13
15
  MAX_RESULTS = 50
14
- PARAMS_SPEC = {"q": "str,可选 关键词(动作名/摘要子串,大小写不敏感)",
16
+ PARAMS_SPEC = {"q": "str,可选 关键词(动作名/摘要/域中文名子串,大小写不敏感)",
15
17
  "domain": "str,可选 限定 erp_* 域工具名"}
16
18
 
17
19
 
18
- def _match(q: str, domain: str, name: str, tool: str, summary: str) -> bool:
20
+ def _match(q: str, domain: str, name: str, tool: str, summary: str, label: str = "") -> bool:
21
+ """关键词匹配:动作名 / 摘要 / **域中文名**。
22
+
23
+ 为什么必须带域中文名:485 条摘要里仅 42 条含中文(其余是英文自动生成),中文查询
24
+ 基本搜不到;域中文名(如「采购/供应商单据」)是手写的,中文只能靠它。
25
+ """
19
26
  if domain and tool != domain:
20
27
  return False
21
28
  if not q:
22
29
  return True
23
30
  needle = q.casefold()
24
- return needle in name.casefold() or needle in (summary or "").casefold()
31
+ return (needle in name.casefold()
32
+ or needle in (summary or "").casefold()
33
+ or needle in (label or "").casefold())
25
34
 
26
35
 
27
36
  def execute(registry: Any, params: Optional[dict] = None) -> Dict[str, Any]:
@@ -31,19 +40,22 @@ def execute(registry: Any, params: Optional[dict] = None) -> Dict[str, Any]:
31
40
  domain = str(p.get("domain") or "")
32
41
  unknown = sorted(set(p) - set(PARAMS_SPEC))
33
42
  results = []
43
+ from .registry import DOMAIN_TOOLS
44
+ labels = {d: str(s.get("label") or "") for d, s in DOMAIN_TOOLS.items()}
34
45
  for tool in sorted(registry.domain_actions):
35
46
  index = set(registry.index_actions.get(tool, ()))
36
47
  for name in registry.domain_actions[tool]:
37
48
  meta = registry.actions.get(name)
38
49
  summary = getattr(meta, "summary", "") if meta else ""
39
- if not _match(q, domain, name, tool, summary):
50
+ if not _match(q, domain, name, tool, summary, labels.get(tool, "")):
40
51
  continue
41
52
  results.append({
42
53
  "action": name,
43
54
  "domain": tool,
44
55
  "summary": summary,
45
56
  "in_index": name in index,
46
- "calls": int(registry.usage_counts.get(name, 0)),
57
+ "calls": _tiering.usage_count(
58
+ getattr(registry, "usage_counts", None) or {}, tool, name),
47
59
  })
48
60
  results.sort(key=lambda r: (r["domain"], r["action"]))
49
61
  payload: Dict[str, Any] = {
@@ -21,7 +21,7 @@ HOT_COUNT_KEY = "__hot_count__"
21
21
  INDEX_PATH = Path(__file__).resolve().parent / "action_index.json"
22
22
  # spec A 原文固定一行(体积恒定:仅 N 为 1-3 位变量)。
23
23
  COLD_LINE_FMT = ('本域另有 {n} 个低频动作(可用但未列出);'
24
- '用 search_actions 查(如 search_actions("对账"))')
24
+ '用 search_actions 查(如 search_actions("采购"))')
25
25
  COLD_LINE_PREFIX = "本域另有"
26
26
 
27
27
 
@@ -98,7 +98,10 @@ def load_index(path: Optional[Path] = None):
98
98
 
99
99
 
100
100
  def load_usage_counts(path: Optional[Path] = None) -> Dict[str, int]:
101
- """渲染/搜索用的 {动作: 调用数};种子/真源计数由 harvest 写入此处。"""
101
+ """渲染/搜索用的 {域|动作: 调用数};真源=本机 Hermes 会话统计(refresh_tiers.py 远端写入)。
102
+
103
+ 键必须带域:动作名跨 17 域不唯一(实测 11 组同名),只按动作名查会互相覆盖。
104
+ """
102
105
  p = INDEX_PATH if path is None else path
103
106
  try:
104
107
  raw = json.loads(p.read_text(encoding="utf-8"))
@@ -81,3 +81,28 @@ class SearchActionsTest(unittest.TestCase):
81
81
 
82
82
  if __name__ == "__main__":
83
83
  unittest.main()
84
+
85
+
86
+ class SearchActionsChineseTest(unittest.TestCase):
87
+ """中文可搜(域中文名)+ calls 按「域|动作」取值(2026-09-18 实测两缺陷的守卫)。"""
88
+
89
+ @classmethod
90
+ def setUpClass(cls):
91
+ cls.reg = MCPRegistry()
92
+
93
+ def test_chinese_domain_label_hit(self):
94
+ out = search_actions.execute(self.reg, {"q": "采购"})
95
+ self.assertGreater(out["total"], 0)
96
+ self.assertIn("erp_purchasing", {r["domain"] for r in out["results"]})
97
+
98
+ def test_cold_line_example_actually_hits(self):
99
+ """提示行举例必须真能查到(曾经举例 "对账" 返回 0 条)。"""
100
+ out = search_actions.execute(self.reg, {"q": "采购"})
101
+ self.assertGreater(out["total"], 0)
102
+
103
+ def test_calls_from_per_domain_usage_key(self):
104
+ reg = MCPRegistry()
105
+ reg.usage_counts = {"erp_partners|list_thirdparty": 101}
106
+ out = search_actions.execute(reg, {"q": "list_thirdparty", "domain": "erp_partners"})
107
+ hit = next(r for r in out["results"] if r["action"] == "list_thirdparty")
108
+ self.assertEqual(hit["calls"], 101)
@@ -72,7 +72,7 @@ class RenderLineTest(unittest.TestCase):
72
72
  self.assertEqual("", tiering.render_cold_line(0))
73
73
  line = tiering.render_cold_line(12)
74
74
  self.assertIn("本域另有 12 个低频动作", line)
75
- self.assertIn('search_actions("对账")', line)
75
+ self.assertIn('search_actions("采购")', line)
76
76
 
77
77
 
78
78
  class RegistryTierRenderTest(unittest.TestCase):
@@ -119,3 +119,18 @@ class RegistryTierRenderTest(unittest.TestCase):
119
119
 
120
120
  if __name__ == "__main__":
121
121
  unittest.main()
122
+
123
+
124
+ class UsageCountTest(unittest.TestCase):
125
+ """同名动作跨域不能互相覆盖(2026-09-18 实测事故回归守卫)。"""
126
+
127
+ def test_prefers_per_domain_key(self):
128
+ usage = {"erp_partners|list_thirdparty": 101, "erp_thirdparty|list_thirdparty": 1}
129
+ self.assertEqual(tiering.usage_count(usage, "erp_partners", "list_thirdparty"), 101)
130
+
131
+ def test_falls_back_to_bare_action_key(self):
132
+ self.assertEqual(
133
+ tiering.usage_count({"list_product": 5}, "erp_products", "list_product"), 5)
134
+
135
+ def test_missing_returns_zero(self):
136
+ self.assertEqual(tiering.usage_count({}, "erp_products", "list_product"), 0)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cli-dolibarr
3
- Version: 3.32.2
3
+ Version: 3.32.4
4
4
  Summary: CLI tool for Dolibarr ERP/CRM REST API management
5
5
  Author: CLI Anything
6
6
  License-Expression: MIT
@@ -120,7 +120,6 @@ cli_dolibarr/dolibarr/tests/test_invoices.py
120
120
  cli_dolibarr/dolibarr/tests/test_mcp_auth.py
121
121
  cli_dolibarr/dolibarr/tests/test_mcp_error_guidance.py
122
122
  cli_dolibarr/dolibarr/tests/test_mcp_field_hints.py
123
- cli_dolibarr/dolibarr/tests/test_mcp_harvest_args.py
124
123
  cli_dolibarr/dolibarr/tests/test_mcp_leak_audit.py
125
124
  cli_dolibarr/dolibarr/tests/test_mcp_list_document_id_ref_guidance.py
126
125
  cli_dolibarr/dolibarr/tests/test_mcp_makeorder_date_backfill.py
@@ -132,7 +131,6 @@ cli_dolibarr/dolibarr/tests/test_mcp_search_actions.py
132
131
  cli_dolibarr/dolibarr/tests/test_mcp_server.py
133
132
  cli_dolibarr/dolibarr/tests/test_mcp_tiering.py
134
133
  cli_dolibarr/dolibarr/tests/test_mcp_transport.py
135
- cli_dolibarr/dolibarr/tests/test_mcp_usage_db.py
136
134
  cli_dolibarr/dolibarr/tests/test_mobilehubapi_aidoc.py
137
135
  cli_dolibarr/dolibarr/tests/test_mobilehubapi_stockin_queued.py
138
136
  cli_dolibarr/dolibarr/tests/test_mos.py
@@ -1 +0,0 @@
1
- __version__ = "3.32.2"
@@ -1,84 +0,0 @@
1
- """S2 harvest.py 单测:args_of 三形状 + SELF_NOISE + 播种幂等(plan S2)。"""
2
- import sqlite3
3
- import sys
4
- import unittest
5
- from pathlib import Path
6
-
7
- REPO_ROOT = str(Path(__file__).resolve().parents[3])
8
- if REPO_ROOT not in sys.path:
9
- sys.path.insert(0, REPO_ROOT)
10
-
11
- import harvest # noqa: E402
12
-
13
-
14
- class ArgsOfTest(unittest.TestCase):
15
- def test_direct_erp_tool(self):
16
- rec = {"type": "tool", "tool": "erp_products",
17
- "state": {"status": "completed",
18
- "input": {"action": "list_product"}}}
19
- self.assertEqual(("erp_products", "list_product"),
20
- harvest.args_of(rec)[:2])
21
-
22
- def test_meta_tool_call_shape(self):
23
- rec = {"type": "tool", "tool": "skill_mcp",
24
- "state": {"status": "completed",
25
- "input": {"mcp_name": "cli-dolibarr",
26
- "tool_name": "erp_system",
27
- "arguments": "{\"action\": \"list_status\"}"}}}
28
- self.assertEqual(("erp_system", "list_status"),
29
- harvest.args_of(rec)[:2])
30
-
31
- def test_openai_function_shape(self):
32
- rec = {"tool_calls": [{"function": {
33
- "name": "erp_invoices",
34
- "arguments": "{\"action\": \"list_invoice\"}"}}]}
35
- self.assertEqual(("erp_invoices", "list_invoice"),
36
- harvest.args_of(rec)[:2])
37
-
38
- def test_self_noise_and_unknown_ignored(self):
39
- self.assertIsNone(harvest.args_of(
40
- {"type": "tool", "tool": "bash",
41
- "state": {"status": "completed", "input": {}}}))
42
- self.assertIsNone(harvest.args_of({"type": "text", "text": "hi"}))
43
- self.assertIsNone(harvest.args_of("not-a-dict"))
44
-
45
- def test_incomplete_call_ignored(self):
46
- rec = {"type": "tool", "tool": "erp_products",
47
- "state": {"status": "running", "input": {}}}
48
- self.assertIsNone(harvest.args_of(rec))
49
-
50
-
51
- class SeedAndAggregateTest(unittest.TestCase):
52
- def setUp(self):
53
- import tempfile
54
- self.tmp = tempfile.TemporaryDirectory()
55
- self.db_path = str(Path(self.tmp.name) / "u.db")
56
-
57
- def tearDown(self):
58
- self.tmp.cleanup()
59
-
60
- def test_aggregate_counts_and_last_ts(self):
61
- rows = [("erp_products", "list_product", 100),
62
- ("erp_products", "list_product", 200),
63
- ("erp_products", "get_product", 150)]
64
- agg = harvest.aggregate(rows)
65
- self.assertEqual(2, agg["list_product"]["calls"])
66
- self.assertEqual(200, agg["list_product"]["last_ts"])
67
- self.assertEqual("erp_products", agg["list_product"]["domain"])
68
-
69
- def test_seed_spec_idempotent(self):
70
- import db
71
- db.init_db(self.db_path)
72
- n1 = harvest.seed_spec(db_path=self.db_path)
73
- n2 = harvest.seed_spec(db_path=self.db_path)
74
- self.assertGreaterEqual(n1, 5)
75
- self.assertEqual(n1, n2)
76
- con = sqlite3.connect(self.db_path)
77
- rows = con.execute(
78
- "SELECT count(*) FROM action_usage WHERE seeded=1").fetchone()[0]
79
- con.close()
80
- self.assertEqual(n1, rows)
81
-
82
-
83
- if __name__ == "__main__":
84
- unittest.main()
@@ -1,76 +0,0 @@
1
- """S1 台账 db.py 单测(plan S1)。运行前提:仓根 db.py 存在。"""
2
- import sqlite3
3
- import sys
4
- import unittest
5
- from pathlib import Path
6
-
7
- REPO_ROOT = str(Path(__file__).resolve().parents[3])
8
- if REPO_ROOT not in sys.path:
9
- sys.path.insert(0, REPO_ROOT)
10
-
11
- import db # noqa: E402
12
-
13
-
14
- class UsageDbTest(unittest.TestCase):
15
- def setUp(self):
16
- import tempfile
17
- self.tmp = tempfile.TemporaryDirectory()
18
- self.db_path = str(Path(self.tmp.name) / "usage.db")
19
-
20
- def tearDown(self):
21
- self.tmp.cleanup()
22
-
23
- def test_init_creates_tables(self):
24
- db.init_db(self.db_path)
25
- con = sqlite3.connect(self.db_path)
26
- names = {r[0] for r in con.execute(
27
- "SELECT name FROM sqlite_master WHERE type='table'")}
28
- con.close()
29
- self.assertIn("action_usage", names)
30
- self.assertIn("nightly_runs", names)
31
-
32
- def test_upsert_idempotent(self):
33
- db.init_db(self.db_path)
34
- row = {"action": "list_product", "domain": "erp_products",
35
- "calls": 2, "last_ts": 1700000000, "window_days": 90}
36
- db.upsert_usage([row], self.db_path)
37
- row2 = dict(row, calls=5)
38
- db.upsert_usage([row2], self.db_path)
39
- con = sqlite3.connect(self.db_path)
40
- n = con.execute("SELECT count(*) FROM action_usage").fetchone()[0]
41
- calls = con.execute(
42
- "SELECT calls FROM action_usage WHERE action='list_product'"
43
- ).fetchone()[0]
44
- con.close()
45
- self.assertEqual(1, n)
46
- self.assertEqual(5, calls)
47
-
48
- def test_get_usage_roundtrip(self):
49
- db.init_db(self.db_path)
50
- rows = [
51
- {"action": "list_product", "domain": "erp_products", "calls": 3,
52
- "last_ts": 1700000000, "window_days": 90},
53
- {"action": "list_warehouse", "domain": "erp_logistics", "calls": 1,
54
- "last_ts": 1700000100, "window_days": 90},
55
- ]
56
- db.upsert_usage(rows, self.db_path)
57
- got = db.get_usage(self.db_path)
58
- self.assertEqual(2, len(got))
59
- self.assertEqual("erp_products", got["list_product"]["domain"])
60
- self.assertEqual(3, got["list_product"]["calls"])
61
- self.assertEqual(1, got["list_warehouse"]["calls"])
62
-
63
- def test_record_run(self):
64
- db.init_db(self.db_path)
65
- db.record_run(stage="toolface_budget", status="ok", note="dry-run",
66
- path=self.db_path)
67
- con = sqlite3.connect(self.db_path)
68
- row = con.execute(
69
- "SELECT stage, status, note FROM nightly_runs "
70
- "ORDER BY id DESC LIMIT 1").fetchone()
71
- con.close()
72
- self.assertEqual(("toolface_budget", "ok", "dry-run"), tuple(row))
73
-
74
-
75
- if __name__ == "__main__":
76
- unittest.main()
File without changes
File without changes
File without changes