cmdbox 0.6.0.4__py3-none-any.whl → 0.6.1__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.

Potentially problematic release.


This version of cmdbox might be problematic. Click here for more details.

Files changed (220) hide show
  1. cmdbox/app/app.py +2 -2
  2. cmdbox/app/auth/signin.py +144 -28
  3. cmdbox/app/common.py +40 -3
  4. cmdbox/app/edge.py +1 -1
  5. cmdbox/app/edge_tool.py +1 -1
  6. cmdbox/app/features/cli/agent_base.py +1 -335
  7. cmdbox/app/features/cli/cmdbox_audit_search.py +0 -2
  8. cmdbox/app/features/cli/cmdbox_audit_write.py +9 -0
  9. cmdbox/app/features/cli/cmdbox_cmd_list.py +1 -1
  10. cmdbox/app/features/cli/cmdbox_cmd_load.py +1 -1
  11. cmdbox/app/features/cli/cmdbox_mcp_proxy.py +90 -0
  12. cmdbox/app/features/cli/cmdbox_web_gencert.py +25 -2
  13. cmdbox/app/features/cli/cmdbox_web_start.py +4 -1
  14. cmdbox/app/features/web/cmdbox_web_signin.py +1 -1
  15. cmdbox/app/mcp.py +375 -0
  16. cmdbox/app/options.py +2 -0
  17. cmdbox/app/web.py +34 -6
  18. cmdbox/autoload.py +10 -0
  19. cmdbox/extensions/user_list.yml +25 -1
  20. cmdbox/licenses/{LICENSE.Deprecated.1.2.18(MIT License).txt → LICENSE_PyJWT_2_10_1_MIT_License.txt} +2 -2
  21. cmdbox/licenses/LICENSE_exceptiongroup_1_3_0_MIT_License.txt +73 -0
  22. cmdbox/licenses/LICENSE_fastmcp_2_9_2_Apache_Software_License.txt +201 -0
  23. cmdbox/licenses/{LICENSE.graphviz.0.20.3(MIT License).txt → LICENSE_graphviz_0_21_UNKNOWN.txt} +1 -1
  24. cmdbox/licenses/LICENSE_jaraco_functools_4_2_1_UNKNOWN.txt +18 -0
  25. cmdbox/licenses/{LICENSE.numpy.2.2.5(BSD License).txt → LICENSE_numpy_2_3_1_BSD_License.txt} +8 -8
  26. cmdbox/licenses/LICENSE_openapi-pydantic_0_5_1_MIT_License.txt +40 -0
  27. cmdbox/licenses/LICENSE_propcache_0_3_2_Apache_Software_License.txt +202 -0
  28. cmdbox/licenses/LICENSE_proto-plus_1_26_1_Apache_Software_License.txt +202 -0
  29. cmdbox/licenses/LICENSE_shellingham_1_5_4_ISC_License-ISCL.txt +13 -0
  30. cmdbox/licenses/LICENSE_sphinx-last-updated-by-git_0_3_8_BSD_License.txt +22 -0
  31. cmdbox/licenses/LICENSE_tenacity_8_5_0_Apache_Software_License.txt +202 -0
  32. cmdbox/licenses/LICENSE_tokenizers_0_21_2_Apache_Software_License.txt +1 -0
  33. cmdbox/licenses/LICENSE_typer_0_16_0_MIT_License.txt +21 -0
  34. cmdbox/licenses/LICENSE_typing-inspection_0_4_1_UNKNOWN.txt +21 -0
  35. cmdbox/licenses/LICENSE_yarl_1_20_1_Apache_Software_License.txt +202 -0
  36. cmdbox/licenses/LICENSE_zipp_3_23_0_UNKNOWN.txt +18 -0
  37. cmdbox/licenses/files.txt +176 -166
  38. cmdbox/logconf_mcp.yml +43 -0
  39. cmdbox/version.py +2 -2
  40. cmdbox/web/agent.html +1 -33
  41. cmdbox/web/assets/cmdbox/audit.js +1 -1
  42. cmdbox/web/assets/cmdbox/common.js +47 -4
  43. cmdbox/web/assets/cmdbox/svgicon.js +122 -0
  44. cmdbox/web/assets/cmdbox/users.js +4 -3
  45. cmdbox/web/audit.html +1 -35
  46. cmdbox/web/filer.html +1 -13
  47. cmdbox/web/gui.html +2 -50
  48. cmdbox/web/result.html +2 -46
  49. cmdbox/web/signin.html +1 -26
  50. cmdbox/web/users.html +1 -41
  51. {cmdbox-0.6.0.4.dist-info → cmdbox-0.6.1.dist-info}/METADATA +31 -6
  52. cmdbox-0.6.1.dist-info/RECORD +383 -0
  53. cmdbox/licenses/LICENSE.keyring.25.6.0(MIT License).txt +0 -17
  54. cmdbox/licenses/LICENSE.typing-inspection.0.4.0(MIT License).txt +0 -21
  55. cmdbox/licenses/LICENSE.wrapt.1.17.2(BSD License).txt +0 -24
  56. cmdbox/licenses/LICENSE.zipp.3.21.0(MIT License).txt +0 -17
  57. cmdbox-0.6.0.4.dist-info/RECORD +0 -368
  58. /cmdbox/licenses/{LICENSE.Authlib.1.5.2(BSD License).txt → LICENSE_Authlib_1_6_0_BSD_License.txt} +0 -0
  59. /cmdbox/licenses/{LICENSE.Jinja2.3.1.6(BSD License).txt → LICENSE_Jinja2_3_1_6_BSD_License.txt} +0 -0
  60. /cmdbox/licenses/{LICENSE.MarkupSafe.3.0.2(BSD License).txt → LICENSE_MarkupSafe_3_0_2_BSD_License.txt} +0 -0
  61. /cmdbox/licenses/{LICENSE.PyYAML.6.0.2(MIT License).txt → LICENSE_PyYAML_6_0_2_MIT_License.txt} +0 -0
  62. /cmdbox/licenses/{LICENSE.Pygments.2.19.1(BSD License).txt → LICENSE_Pygments_2_19_2_BSD_License.txt} +0 -0
  63. /cmdbox/licenses/{LICENSE.SQLAlchemy.2.0.40(MIT License).txt → LICENSE_SQLAlchemy_2_0_41_MIT.txt} +0 -0
  64. /cmdbox/licenses/{LICENSE.Sphinx.8.2.3(UNKNOWN).txt → LICENSE_Sphinx_8_2_3_UNKNOWN.txt} +0 -0
  65. /cmdbox/licenses/{LICENSE.aiohappyeyeballs.2.6.1(Python Software Foundation License).txt → LICENSE_aiohappyeyeballs_2_6_1_Python_Software_Foundation_License.txt} +0 -0
  66. /cmdbox/licenses/{LICENSE.aiohttp.3.11.18(Apache Software License).txt → LICENSE_aiohttp_3_12_13_Apache-2_0.txt} +0 -0
  67. /cmdbox/licenses/{LICENSE.aiosignal.1.3.2(Apache Software License).txt → LICENSE_aiosignal_1_3_2_Apache_Software_License.txt} +0 -0
  68. /cmdbox/licenses/{LICENSE.alabaster.1.0.0(BSD License).txt → LICENSE_alabaster_1_0_0_BSD_License.txt} +0 -0
  69. /cmdbox/licenses/{LICENSE.annotated-types.0.7.0(MIT License).txt → LICENSE_annotated-types_0_7_0_MIT_License.txt} +0 -0
  70. /cmdbox/licenses/{LICENSE.anyio.4.9.0(MIT License).txt → LICENSE_anyio_4_9_0_MIT_License.txt} +0 -0
  71. /cmdbox/licenses/{LICENSE.argcomplete.3.6.2(Apache Software License).txt → LICENSE_argcomplete_3_6_2_Apache_Software_License.txt} +0 -0
  72. /cmdbox/licenses/{LICENSE.async-timeout.5.0.1(Apache Software License).txt → LICENSE_async-timeout_5_0_1_Apache_Software_License.txt} +0 -0
  73. /cmdbox/licenses/{LICENSE.attrs.25.3.0(UNKNOWN).txt → LICENSE_attrs_25_3_0_UNKNOWN.txt} +0 -0
  74. /cmdbox/licenses/{LICENSE.babel.2.17.0(BSD License).txt → LICENSE_babel_2_17_0_BSD_License.txt} +0 -0
  75. /cmdbox/licenses/{LICENSE.backports.tarfile.1.2.0(MIT License).txt → LICENSE_backports_tarfile_1_2_0_MIT_License.txt} +0 -0
  76. /cmdbox/licenses/{LICENSE.cachetools.5.5.2(MIT License).txt → LICENSE_cachetools_5_5_2_MIT_License.txt} +0 -0
  77. /cmdbox/licenses/{LICENSE.certifi.2025.4.26(Mozilla Public License 2.0 (MPL 2.0)).txt → LICENSE_certifi_2025_6_15_Mozilla_Public_License_2_0-MPL_2_0.txt} +0 -0
  78. /cmdbox/licenses/{LICENSE.cffi.1.17.1(MIT License).txt → LICENSE_cffi_1_17_1_MIT_License.txt} +0 -0
  79. /cmdbox/licenses/{LICENSE.charset-normalizer.3.4.2(MIT License).txt → LICENSE_charset-normalizer_3_4_2_MIT_License.txt} +0 -0
  80. /cmdbox/licenses/{LICENSE.click.8.2.0(UNKNOWN).txt → LICENSE_click_8_2_1_UNKNOWN.txt} +0 -0
  81. /cmdbox/licenses/{LICENSE.jiter.0.9.0(MIT License).txt → LICENSE_cloudpickle_3_1_1_BSD_License.txt} +0 -0
  82. /cmdbox/licenses/{LICENSE.colorama.0.4.6(BSD License).txt → LICENSE_colorama_0_4_6_BSD_License.txt} +0 -0
  83. /cmdbox/licenses/{LICENSE.cryptography.44.0.3(Apache Software License; BSD License).txt → LICENSE_cryptography_45_0_4_Apache-2_0_OR_BSD-3-Clause.txt} +0 -0
  84. /cmdbox/licenses/{LICENSE.distro.1.9.0(Apache Software License).txt → LICENSE_distro_1_9_0_Apache_Software_License.txt} +0 -0
  85. /cmdbox/licenses/{LICENSE.docstring_parser.0.16(MIT License).txt → LICENSE_docstring_parser_0_16_MIT_License.txt} +0 -0
  86. /cmdbox/licenses/{LICENSE.docutils.0.21.2(BSD License; GNU General Public License (GPL); Public Domain; Python Software Foundation License).txt → LICENSE_docutils_0_21_2_BSD_License-GNU_General_Public_License-GPL-Public_Domain-Python_Software_Foundation_License.txt} +0 -0
  87. /cmdbox/licenses/{LICENSE.fastapi.0.115.12(MIT License).txt → LICENSE_fastapi_0_115_14_MIT_License.txt} +0 -0
  88. /cmdbox/licenses/{LICENSE.filelock.3.18.0(The Unlicense (Unlicense)).txt → LICENSE_filelock_3_18_0_The_Unlicense-Unlicense.txt} +0 -0
  89. /cmdbox/licenses/{LICENSE.frozenlist.1.6.0(Apache-2.0).txt → LICENSE_frozenlist_1_7_0_Apache-2_0.txt} +0 -0
  90. /cmdbox/licenses/{LICENSE.fsspec.2025.3.2(BSD License).txt → LICENSE_fsspec_2025_5_1_BSD_License.txt} +0 -0
  91. /cmdbox/licenses/{LICENSE.gevent.25.4.2(MIT).txt → LICENSE_gevent_25_5_1_MIT.txt} +0 -0
  92. /cmdbox/licenses/{LICENSE.google-adk.0.5.0(Apache Software License).txt → LICENSE_google-adk_1_5_0_Apache_Software_License.txt} +0 -0
  93. /cmdbox/licenses/{LICENSE.google-api-core.2.24.2(Apache Software License).txt → LICENSE_google-api-core_2_25_1_Apache_Software_License.txt} +0 -0
  94. /cmdbox/licenses/{LICENSE.google-api-python-client.2.169.0(Apache Software License).txt → LICENSE_google-api-python-client_2_174_0_Apache_Software_License.txt} +0 -0
  95. /cmdbox/licenses/{LICENSE.google-auth-httplib2.0.2.0(Apache Software License).txt → LICENSE_google-auth-httplib2_0_2_0_Apache_Software_License.txt} +0 -0
  96. /cmdbox/licenses/{LICENSE.google-auth.2.40.1(Apache Software License).txt → LICENSE_google-auth_2_40_3_Apache_Software_License.txt} +0 -0
  97. /cmdbox/licenses/{LICENSE.google-cloud-aiplatform.1.92.0(Apache 2.0).txt → LICENSE_google-cloud-aiplatform_1_100_0_Apache_2_0.txt} +0 -0
  98. /cmdbox/licenses/{LICENSE.google-cloud-bigquery.3.31.0(Apache Software License).txt → LICENSE_google-cloud-appengine-logging_1_6_2_Apache_Software_License.txt} +0 -0
  99. /cmdbox/licenses/{LICENSE.google-cloud-core.2.4.3(Apache Software License).txt → LICENSE_google-cloud-audit-log_0_3_2_Apache_Software_License.txt} +0 -0
  100. /cmdbox/licenses/{LICENSE.google-cloud-resource-manager.1.14.2(Apache Software License).txt → LICENSE_google-cloud-bigquery_3_34_0_Apache_Software_License.txt} +0 -0
  101. /cmdbox/licenses/{LICENSE.google-cloud-secret-manager.2.23.3(Apache Software License).txt → LICENSE_google-cloud-core_2_4_3_Apache_Software_License.txt} +0 -0
  102. /cmdbox/licenses/{LICENSE.google-cloud-speech.2.32.0(Apache Software License).txt → LICENSE_google-cloud-logging_3_12_1_Apache_Software_License.txt} +0 -0
  103. /cmdbox/licenses/{LICENSE.google-cloud-storage.2.19.0(Apache Software License).txt → LICENSE_google-cloud-resource-manager_1_14_2_Apache_Software_License.txt} +0 -0
  104. /cmdbox/licenses/{LICENSE.google-cloud-trace.1.16.1(Apache Software License).txt → LICENSE_google-cloud-secret-manager_2_24_0_Apache_Software_License.txt} +0 -0
  105. /cmdbox/licenses/{LICENSE.google-crc32c.1.7.1(Apache 2.0).txt → LICENSE_google-cloud-speech_2_33_0_Apache_Software_License.txt} +0 -0
  106. /cmdbox/licenses/{LICENSE.google-genai.1.14.0(Apache Software License).txt → LICENSE_google-cloud-storage_2_19_0_Apache_Software_License.txt} +0 -0
  107. /cmdbox/licenses/{LICENSE.google-resumable-media.2.7.2(Apache Software License).txt → LICENSE_google-cloud-trace_1_16_2_Apache_Software_License.txt} +0 -0
  108. /cmdbox/licenses/{LICENSE.googleapis-common-protos.1.70.0(Apache Software License).txt → LICENSE_google-crc32c_1_7_1_Apache_2_0.txt} +0 -0
  109. /cmdbox/licenses/{LICENSE.grpc-google-iam-v1.0.14.2(Apache Software License).txt → LICENSE_google-genai_1_23_0_Apache_Software_License.txt} +0 -0
  110. /cmdbox/licenses/{LICENSE.id.1.5.0(Apache Software License).txt → LICENSE_google-resumable-media_2_7_2_Apache_Software_License.txt} +0 -0
  111. /cmdbox/licenses/{LICENSE.importlib_metadata.8.6.1(Apache Software License).txt → LICENSE_googleapis-common-protos_1_70_0_Apache_Software_License.txt} +0 -0
  112. /cmdbox/licenses/{LICENSE.greenlet.3.2.2(MIT AND Python-2.0).txt → LICENSE_greenlet_3_2_3_MIT_AND_Python-2_0.txt} +0 -0
  113. /cmdbox/licenses/{LICENSE.propcache.0.3.1(Apache Software License).txt → LICENSE_grpc-google-iam-v1_0_14_2_Apache_Software_License.txt} +0 -0
  114. /cmdbox/licenses/{LICENSE.grpcio-status.1.71.0(Apache Software License).txt → LICENSE_grpcio-status_1_73_1_Apache_Software_License.txt} +0 -0
  115. /cmdbox/licenses/{LICENSE.grpcio.1.71.0(Apache Software License).txt → LICENSE_grpcio_1_73_1_Apache_Software_License.txt} +0 -0
  116. /cmdbox/licenses/{LICENSE.gunicorn.23.0.0(MIT License).txt → LICENSE_gunicorn_23_0_0_MIT_License.txt} +0 -0
  117. /cmdbox/licenses/{LICENSE.h11.0.16.0(MIT License).txt → LICENSE_h11_0_16_0_MIT_License.txt} +0 -0
  118. /cmdbox/licenses/{LICENSE.httpcore.1.0.9(BSD License).txt → LICENSE_httpcore_1_0_9_BSD_License.txt} +0 -0
  119. /cmdbox/licenses/{LICENSE.httplib2.0.22.0(MIT License).txt → LICENSE_httplib2_0_22_0_MIT_License.txt} +0 -0
  120. /cmdbox/licenses/{LICENSE.httptools.0.6.4(MIT License).txt → LICENSE_httptools_0_6_4_MIT_License.txt} +0 -0
  121. /cmdbox/licenses/{LICENSE.httpx-sse.0.4.0(MIT).txt → LICENSE_httpx-sse_0_4_1_MIT.txt} +0 -0
  122. /cmdbox/licenses/{LICENSE.httpx.0.28.1(BSD License).txt → LICENSE_httpx_0_28_1_BSD_License.txt} +0 -0
  123. /cmdbox/licenses/{LICENSE.huggingface-hub.0.31.1(Apache Software License).txt → LICENSE_huggingface-hub_0_33_1_Apache_Software_License.txt} +0 -0
  124. /cmdbox/licenses/{LICENSE.proto-plus.1.26.1(Apache Software License).txt → LICENSE_id_1_5_0_Apache_Software_License.txt} +0 -0
  125. /cmdbox/licenses/{LICENSE.idna.3.10(BSD License).txt → LICENSE_idna_3_10_BSD_License.txt} +0 -0
  126. /cmdbox/licenses/{LICENSE.imagesize.1.4.1(MIT License).txt → LICENSE_imagesize_1_4_1_MIT_License.txt} +0 -0
  127. /cmdbox/licenses/{LICENSE.yarl.1.20.0(Apache Software License).txt → LICENSE_importlib_metadata_8_7_0_Apache_Software_License.txt} +0 -0
  128. /cmdbox/licenses/{LICENSE.itsdangerous.2.2.0(BSD License).txt → LICENSE_itsdangerous_2_2_0_BSD_License.txt} +0 -0
  129. /cmdbox/licenses/{LICENSE.jaraco.classes.3.4.0(MIT License).txt → LICENSE_jaraco_classes_3_4_0_MIT_License.txt} +0 -0
  130. /cmdbox/licenses/{LICENSE.jaraco.context.6.0.1(MIT License).txt → LICENSE_jaraco_context_6_0_1_MIT_License.txt} +0 -0
  131. /cmdbox/licenses/{LICENSE.sphinxcontrib-applehelp.2.0.0(BSD License).txt → LICENSE_jiter_0_10_0_MIT_License.txt} +0 -0
  132. /cmdbox/licenses/{LICENSE.jsonschema-specifications.2025.4.1(UNKNOWN).txt → LICENSE_jsonschema-specifications_2025_4_1_UNKNOWN.txt} +0 -0
  133. /cmdbox/licenses/{LICENSE.jsonschema.4.23.0(MIT License).txt → LICENSE_jsonschema_4_24_0_UNKNOWN.txt} +0 -0
  134. /cmdbox/licenses/{LICENSE.jaraco.functools.4.1.0(MIT License).txt → LICENSE_keyring_25_6_0_MIT_License.txt} +0 -0
  135. /cmdbox/licenses/{LICENSE.litellm.1.69.0(MIT License).txt → LICENSE_litellm_1_73_6_MIT_License.txt} +0 -0
  136. /cmdbox/licenses/{LICENSE.markdown-it-py.3.0.0(MIT License).txt → LICENSE_markdown-it-py_3_0_0_MIT_License.txt} +0 -0
  137. /cmdbox/licenses/{LICENSE.mcp.1.8.0(MIT License).txt → LICENSE_mcp_1_9_4_MIT_License.txt} +0 -0
  138. /cmdbox/licenses/{LICENSE.mdurl.0.1.2(MIT License).txt → LICENSE_mdurl_0_1_2_MIT_License.txt} +0 -0
  139. /cmdbox/licenses/{LICENSE.more-itertools.10.7.0(MIT License).txt → LICENSE_more-itertools_10_7_0_MIT_License.txt} +0 -0
  140. /cmdbox/licenses/{LICENSE.multidict.6.4.3(Apache Software License).txt → LICENSE_multidict_6_6_2_Apache_License_2_0.txt} +0 -0
  141. /cmdbox/licenses/{LICENSE.nh3.0.2.21(MIT).txt → LICENSE_nh3_0_2_21_MIT.txt} +0 -0
  142. /cmdbox/licenses/{LICENSE.openai.1.75.0(Apache Software License).txt → LICENSE_openai_1_93_0_Apache_Software_License.txt} +0 -0
  143. /cmdbox/licenses/{LICENSE.opentelemetry-api.1.33.0(Apache Software License).txt → LICENSE_opentelemetry-api_1_34_1_Apache_Software_License.txt} +0 -0
  144. /cmdbox/licenses/{LICENSE.opentelemetry-exporter-gcp-trace.1.9.0(Apache Software License).txt → LICENSE_opentelemetry-exporter-gcp-trace_1_9_0_Apache_Software_License.txt} +0 -0
  145. /cmdbox/licenses/{LICENSE.opentelemetry-resourcedetector-gcp.1.9.0a0(Apache Software License).txt → LICENSE_opentelemetry-resourcedetector-gcp_1_9_0a0_Apache_Software_License.txt} +0 -0
  146. /cmdbox/licenses/{LICENSE.opentelemetry-sdk.1.33.0(Apache Software License).txt → LICENSE_opentelemetry-sdk_1_34_1_Apache_Software_License.txt} +0 -0
  147. /cmdbox/licenses/{LICENSE.opentelemetry-semantic-conventions.0.54b0(Apache Software License).txt → LICENSE_opentelemetry-semantic-conventions_0_55b1_Apache_Software_License.txt} +0 -0
  148. /cmdbox/licenses/{LICENSE.packaging.25.0(Apache Software License; BSD License).txt → LICENSE_packaging_25_0_Apache_Software_License-BSD_License.txt} +0 -0
  149. /cmdbox/licenses/{LICENSE.pillow.11.2.1(UNKNOWN).txt → LICENSE_pillow_11_2_1_UNKNOWN.txt} +0 -0
  150. /cmdbox/licenses/{LICENSE.pip.24.0(MIT License).txt → LICENSE_pip_24_0_MIT_License.txt} +0 -0
  151. /cmdbox/licenses/{LICENSE.plyer.2.1.0(MIT License).txt → LICENSE_plyer_2_1_0_MIT_License.txt} +0 -0
  152. /cmdbox/licenses/{LICENSE.prettytable.3.16.0(UNKNOWN).txt → LICENSE_prettytable_3_16_0_UNKNOWN.txt} +0 -0
  153. /cmdbox/licenses/{LICENSE.prompt_toolkit.3.0.51(BSD License).txt → LICENSE_prompt_toolkit_3_0_51_BSD_License.txt} +0 -0
  154. /cmdbox/licenses/{LICENSE.protobuf.5.29.4(3-Clause BSD License).txt → LICENSE_protobuf_6_31_1_3-Clause_BSD_License.txt} +0 -0
  155. /cmdbox/licenses/{LICENSE.psycopg-binary.3.2.7(GNU Lesser General Public License v3 (LGPLv3)).txt → LICENSE_psycopg-binary_3_2_9_GNU_Lesser_General_Public_License_v3-LGPLv3.txt} +0 -0
  156. /cmdbox/licenses/{LICENSE.psycopg.3.2.7(GNU Lesser General Public License v3 (LGPLv3)).txt → LICENSE_psycopg_3_2_9_GNU_Lesser_General_Public_License_v3-LGPLv3.txt} +0 -0
  157. /cmdbox/licenses/{LICENSE.pyasn1.0.6.1(BSD License).txt → LICENSE_pyasn1_0_6_1_BSD_License.txt} +0 -0
  158. /cmdbox/licenses/{LICENSE.pyasn1_modules.0.4.2(BSD License).txt → LICENSE_pyasn1_modules_0_4_2_BSD_License.txt} +0 -0
  159. /cmdbox/licenses/{LICENSE.pycparser.2.22(BSD License).txt → LICENSE_pycparser_2_22_BSD_License.txt} +0 -0
  160. /cmdbox/licenses/{LICENSE.pycryptodome.3.22.0(BSD License; Public Domain).txt → LICENSE_pycryptodome_3_23_0_BSD_License-Public_Domain.txt} +0 -0
  161. /cmdbox/licenses/{LICENSE.pydantic-settings.2.9.1(MIT License).txt → LICENSE_pydantic-settings_2_10_1_MIT_License.txt} +0 -0
  162. /cmdbox/licenses/{LICENSE.pydantic.2.11.4(MIT License).txt → LICENSE_pydantic_2_11_7_MIT_License.txt} +0 -0
  163. /cmdbox/licenses/{LICENSE.pydantic_core.2.33.2(MIT License).txt → LICENSE_pydantic_core_2_33_2_MIT_License.txt} +0 -0
  164. /cmdbox/licenses/{LICENSE.pyparsing.3.2.3(MIT License).txt → LICENSE_pyparsing_3_2_3_MIT_License.txt} +0 -0
  165. /cmdbox/licenses/{LICENSE.pystray.0.19.5(GNU Lesser General Public License v3 (LGPLv3)).txt → LICENSE_pystray_0_19_5_GNU_Lesser_General_Public_License_v3-LGPLv3.txt} +0 -0
  166. /cmdbox/licenses/{LICENSE.python-dateutil.2.9.0.post0(Apache Software License; BSD License).txt → LICENSE_python-dateutil_2_9_0_post0_Apache_Software_License-BSD_License.txt} +0 -0
  167. /cmdbox/licenses/{LICENSE.python-dotenv.1.1.0(BSD License).txt → LICENSE_python-dotenv_1_1_1_BSD_License.txt} +0 -0
  168. /cmdbox/licenses/{LICENSE.python-multipart.0.0.20(Apache Software License).txt → LICENSE_python-multipart_0_0_20_Apache_Software_License.txt} +0 -0
  169. /cmdbox/licenses/{LICENSE.pywin32-ctypes.0.2.3(BSD-3-Clause).txt → LICENSE_pywin32-ctypes_0_2_3_BSD-3-Clause.txt} +0 -0
  170. /cmdbox/licenses/{LICENSE.questionary.2.1.0(MIT License).txt → LICENSE_questionary_2_1_0_MIT_License.txt} +0 -0
  171. /cmdbox/licenses/{LICENSE.readme_renderer.44.0(Apache Software License).txt → LICENSE_readme_renderer_44_0_Apache_Software_License.txt} +0 -0
  172. /cmdbox/licenses/{LICENSE.redis.6.0.0(MIT License).txt → LICENSE_redis_6_2_0_MIT_License.txt} +0 -0
  173. /cmdbox/licenses/{LICENSE.referencing.0.36.2(UNKNOWN).txt → LICENSE_referencing_0_36_2_UNKNOWN.txt} +0 -0
  174. /cmdbox/licenses/{LICENSE.regex.2024.11.6(Apache Software License).txt → LICENSE_regex_2024_11_6_Apache_Software_License.txt} +0 -0
  175. /cmdbox/licenses/{LICENSE.requests-toolbelt.1.0.0(Apache Software License).txt → LICENSE_requests-toolbelt_1_0_0_Apache_Software_License.txt} +0 -0
  176. /cmdbox/licenses/{LICENSE.requests.2.32.3(Apache Software License).txt → LICENSE_requests_2_32_4_Apache_Software_License.txt} +0 -0
  177. /cmdbox/licenses/{LICENSE.rfc3986.2.0.0(Apache Software License).txt → LICENSE_rfc3986_2_0_0_Apache_Software_License.txt} +0 -0
  178. /cmdbox/licenses/{LICENSE.rich.14.0.0(MIT License).txt → LICENSE_rich_14_0_0_MIT_License.txt} +0 -0
  179. /cmdbox/licenses/{LICENSE.roman-numerals-py.3.1.0(CC0 1.0 Universal (CC0 1.0) Public Domain Dedication; Zero-Clause BSD (0BSD)).txt → LICENSE_roman-numerals-py_3_1_0_CC0_1_0_Universal-CC0_1_0-Public_Domain_Dedication-Zero-Clause_BSD-0BSD.txt} +0 -0
  180. /cmdbox/licenses/{LICENSE.rpds-py.0.24.0(MIT).txt → LICENSE_rpds-py_0_25_1_MIT.txt} +0 -0
  181. /cmdbox/licenses/{LICENSE.rsa.4.9.1(Apache Software License).txt → LICENSE_rsa_4_9_1_Apache_Software_License.txt} +0 -0
  182. /cmdbox/licenses/{LICENSE.setuptools.65.5.0(MIT License).txt → LICENSE_setuptools_65_5_0_MIT_License.txt} +0 -0
  183. /cmdbox/licenses/{LICENSE.shapely.2.1.0(BSD License).txt → LICENSE_shapely_2_1_1_BSD_License.txt} +0 -0
  184. /cmdbox/licenses/{LICENSE.six.1.17.0(MIT License).txt → LICENSE_six_1_17_0_MIT_License.txt} +0 -0
  185. /cmdbox/licenses/{LICENSE.sniffio.1.3.1(Apache Software License; MIT License).txt → LICENSE_sniffio_1_3_1_Apache_Software_License-MIT_License.txt} +0 -0
  186. /cmdbox/licenses/{LICENSE.snowballstemmer.3.0.1(BSD License).txt → LICENSE_snowballstemmer_3_0_1_BSD_License.txt} +0 -0
  187. /cmdbox/licenses/{LICENSE.sphinx-intl.2.3.1(BSD License).txt → LICENSE_sphinx-intl_2_3_1_BSD_License.txt} +0 -0
  188. /cmdbox/licenses/{LICENSE.sphinx-rtd-theme.3.0.2(MIT License).txt → LICENSE_sphinx-rtd-theme_3_0_2_MIT_License.txt} +0 -0
  189. /cmdbox/licenses/{LICENSE.sphinx-sitemap.2.6.0(MIT License).txt → LICENSE_sphinx-sitemap_2_7_2_UNKNOWN.txt} +0 -0
  190. /cmdbox/licenses/{LICENSE.sphinx_fontawesome.0.0.6(GNU General Public License v2 (GPLv2)).txt → LICENSE_sphinx_fontawesome_0_0_6_GNU_General_Public_License_v2-GPLv2.txt} +0 -0
  191. /cmdbox/licenses/{LICENSE.sphinxcontrib-devhelp.2.0.0(BSD License).txt → LICENSE_sphinxcontrib-applehelp_2_0_0_BSD_License.txt} +0 -0
  192. /cmdbox/licenses/{LICENSE.sphinxcontrib-htmlhelp.2.1.0(BSD License).txt → LICENSE_sphinxcontrib-devhelp_2_0_0_BSD_License.txt} +0 -0
  193. /cmdbox/licenses/{LICENSE.sphinxcontrib-jquery.4.1(BSD License).txt → LICENSE_sphinxcontrib-htmlhelp_2_1_0_BSD_License.txt} +0 -0
  194. /cmdbox/licenses/{LICENSE.sphinxcontrib-qthelp.2.0.0(BSD License).txt → LICENSE_sphinxcontrib-jquery_4_1_BSD_License.txt} +0 -0
  195. /cmdbox/licenses/{LICENSE.sphinxcontrib-jsmath.1.0.1(BSD License).txt → LICENSE_sphinxcontrib-jsmath_1_0_1_BSD_License.txt} +0 -0
  196. /cmdbox/licenses/{LICENSE.sphinxcontrib-serializinghtml.2.0.0(BSD License).txt → LICENSE_sphinxcontrib-qthelp_2_0_0_BSD_License.txt} +0 -0
  197. /cmdbox/licenses/{LICENSE.tokenizers.0.21.1(Apache Software License).txt → LICENSE_sphinxcontrib-serializinghtml_2_0_0_BSD_License.txt} +0 -0
  198. /cmdbox/licenses/{LICENSE.sse-starlette.2.3.4(BSD License).txt → LICENSE_sse-starlette_2_3_6_BSD_License.txt} +0 -0
  199. /cmdbox/licenses/{LICENSE.starlette.0.46.2(BSD License).txt → LICENSE_starlette_0_46_2_BSD_License.txt} +0 -0
  200. /cmdbox/licenses/{LICENSE.tabulate.0.9.0(MIT License).txt → LICENSE_tabulate_0_9_0_MIT_License.txt} +0 -0
  201. /cmdbox/licenses/{LICENSE.tiktoken.0.9.0(MIT License).txt → LICENSE_tiktoken_0_9_0_MIT_License-Copyright-c-2022_OpenAI-Shantanu_Jain-Permission_is_hereby_granted-free_of_charge-to_any_pers.txt} +0 -0
  202. /cmdbox/licenses/{LICENSE.tomli.2.2.1(MIT License).txt → LICENSE_tomli_2_2_1_MIT_License.txt} +0 -0
  203. /cmdbox/licenses/{LICENSE.tqdm.4.67.1(MIT License; Mozilla Public License 2.0 (MPL 2.0)).txt → LICENSE_tqdm_4_67_1_MIT_License-Mozilla_Public_License_2_0-MPL_2_0.txt} +0 -0
  204. /cmdbox/licenses/{LICENSE.twine.6.1.0(Apache Software License).txt → LICENSE_twine_6_1_0_Apache_Software_License.txt} +0 -0
  205. /cmdbox/licenses/{LICENSE.typing_extensions.4.13.2(UNKNOWN).txt → LICENSE_typing_extensions_4_14_0_UNKNOWN.txt} +0 -0
  206. /cmdbox/licenses/{LICENSE.tzdata.2025.2(Apache Software License).txt → LICENSE_tzdata_2025_2_Apache_Software_License.txt} +0 -0
  207. /cmdbox/licenses/{LICENSE.tzlocal.5.3.1(MIT License).txt → LICENSE_tzlocal_5_3_1_MIT_License.txt} +0 -0
  208. /cmdbox/licenses/{LICENSE.uritemplate.4.1.1(Apache Software License; BSD License).txt → LICENSE_uritemplate_4_2_0_BSD_3-Clause_OR_Apache-2_0.txt} +0 -0
  209. /cmdbox/licenses/{LICENSE.urllib3.2.4.0(UNKNOWN).txt → LICENSE_urllib3_2_5_0_UNKNOWN.txt} +0 -0
  210. /cmdbox/licenses/{LICENSE.uvicorn.0.34.2(BSD License).txt → LICENSE_uvicorn_0_35_0_BSD_License.txt} +0 -0
  211. /cmdbox/licenses/{LICENSE.watchfiles.1.0.5(MIT License).txt → LICENSE_watchfiles_1_1_0_MIT_License.txt} +0 -0
  212. /cmdbox/licenses/{LICENSE.wcwidth.0.2.13(MIT License).txt → LICENSE_wcwidth_0_2_13_MIT_License.txt} +0 -0
  213. /cmdbox/licenses/{LICENSE.websockets.15.0.1(BSD License).txt → LICENSE_websockets_15_0_1_BSD_License.txt} +0 -0
  214. /cmdbox/licenses/{LICENSE.wheel.0.45.1(MIT License).txt → LICENSE_wheel_0_45_1_MIT_License.txt} +0 -0
  215. /cmdbox/licenses/{LICENSE.zope.event.5.0(Zope Public License).txt → LICENSE_zope_event_5_1_Zope_Public_License.txt} +0 -0
  216. /cmdbox/licenses/{LICENSE.zope.interface.7.2(Zope Public License).txt → LICENSE_zope_interface_7_2_Zope_Public_License.txt} +0 -0
  217. {cmdbox-0.6.0.4.dist-info → cmdbox-0.6.1.dist-info}/LICENSE +0 -0
  218. {cmdbox-0.6.0.4.dist-info → cmdbox-0.6.1.dist-info}/WHEEL +0 -0
  219. {cmdbox-0.6.0.4.dist-info → cmdbox-0.6.1.dist-info}/entry_points.txt +0 -0
  220. {cmdbox-0.6.0.4.dist-info → cmdbox-0.6.1.dist-info}/top_level.txt +0 -0
cmdbox/app/mcp.py ADDED
@@ -0,0 +1,375 @@
1
+ from cmdbox.app import common, options
2
+ from cmdbox.app.options import Options
3
+ from cmdbox.app.auth import signin
4
+ from pathlib import Path
5
+ from typing import Callable, List, Dict, Any, Tuple
6
+ import argparse
7
+ import logging
8
+ import locale
9
+ import json
10
+ import time
11
+ import re
12
+ import os
13
+
14
+
15
+ class Mcp:
16
+ default_host:str = os.environ.get('REDIS_HOST', 'localhost')
17
+ default_port:int = int(os.environ.get('REDIS_PORT', '6379'))
18
+ default_pass:str = os.environ.get('REDIS_PASSWORD', 'password')
19
+ default_svname:str = os.environ.get('SVNAME', 'server')
20
+
21
+ def __init__(self, logger:logging.Logger, data:Path, sign:signin.Signin, appcls=None, ver=None,):
22
+ """
23
+ MCP (Multi-Channel Protocol) クラスの初期化
24
+
25
+ Args:
26
+ logger (logging.Logger): ロガー
27
+ data (Path): データのパス
28
+ sign (signin.Signin): サインインオブジェクト
29
+ appcls (type, optional): アプリケーションクラス. Defaults to None.
30
+ ver (module, optional): バージョンモジュール. Defaults to None.
31
+ """
32
+ self.logger = logger
33
+ self.data = data
34
+ self.appcls = appcls
35
+ self.ver = ver
36
+ self.signin = sign
37
+
38
+ def create_mcpserver(self, args:argparse.Namespace) -> Any:
39
+ """
40
+ mcpserverを作成します
41
+
42
+ Args:
43
+ args (argparse.Namespace): 引数
44
+
45
+ Returns:
46
+ Any: FastMCP
47
+ """
48
+ from fastmcp import FastMCP
49
+ from fastmcp.server.auth import BearerAuthProvider
50
+ cls = self.signin.__class__
51
+ publickey_str = cls.verify_jwt_publickey_str if hasattr(cls, 'verify_jwt_publickey_str') else None
52
+ issuer = cls.verify_jwt_issuer if hasattr(cls, 'verify_jwt_issuer') else None
53
+ audience = cls.verify_jwt_audience if hasattr(cls, 'verify_jwt_audience') else None
54
+ if publickey_str is not None and issuer is not None and audience is not None:
55
+ self.logger.info(f"Using BearerAuthProvider with public key, issuer: {issuer}, audience: {audience}")
56
+ auth = BearerAuthProvider(
57
+ public_key=publickey_str,
58
+ issuer=issuer,
59
+ audience=audience
60
+ )
61
+ mcp = FastMCP(name=self.ver.__appid__, auth=auth)
62
+ else:
63
+ self.logger.info(f"Using BearerAuthProvider without public key, issuer, or audience.")
64
+ mcp = FastMCP(name=self.ver.__appid__)
65
+ return mcp
66
+
67
+ def create_session_service(self, args:argparse.Namespace) -> Any:
68
+ """
69
+ セッションサービスを作成します
70
+
71
+ Args:
72
+ args (argparse.Namespace): 引数
73
+
74
+ Returns:
75
+ BaseSessionService: セッションサービス
76
+ """
77
+ from google.adk.events import Event
78
+ from google.adk.sessions import DatabaseSessionService, InMemorySessionService, session
79
+ from typing_extensions import override
80
+ if hasattr(args, 'agent_session_dburl') and args.agent_session_dburl is not None:
81
+ class _DatabaseSessionService(DatabaseSessionService):
82
+ @override
83
+ async def append_event(self, session: session.Session, event: Event) -> Event:
84
+ # 永続化されるセッションには <important> タグを含めない
85
+ bk_parts = event.content.parts.copy()
86
+ for part in event.content.parts:
87
+ if not part.text: continue
88
+ part.text = re.sub(r"<important>.*</important>", "", part.text)
89
+ for part in bk_parts:
90
+ if not part.text: continue
91
+ part.text = part.text.replace("<important>", "").replace("</important>", "")
92
+ ret = await super().append_event(session, event)
93
+ ret.content.parts = bk_parts
94
+ return ret
95
+ dss = _DatabaseSessionService(db_url=args.agent_session_dburl)
96
+ #dss.db_engine.echo = True
97
+ return dss
98
+ else:
99
+ return InMemorySessionService()
100
+
101
+ def create_agent(self, logger:logging.Logger, args:argparse.Namespace, tools:List[Callable]) -> Any:
102
+ """
103
+ エージェントを作成します
104
+
105
+ Args:
106
+ logger (logging.Logger): ロガー
107
+ args (argparse.Namespace): 引数
108
+ tools (List[Callable]): 関数
109
+
110
+ Returns:
111
+ Agent: エージェント
112
+ """
113
+ if logger.level == logging.DEBUG:
114
+ logger.debug(f"create_agent processing..")
115
+ language, _ = locale.getlocale()
116
+ is_japan = language.find('Japan') >= 0 or language.find('ja_JP') >= 0
117
+ description = f"{self.ver.__appid__}に登録されているコマンド提供"
118
+ instruction = f"あなたはコマンドの意味を熟知しているエキスパートです。" + \
119
+ f"ユーザーがコマンドを実行したいとき、あなたは以下の手順に従ってコマンドを確実に実行してください。\n" + \
120
+ f"1. ユーザーのクエリからが実行したいコマンドを特定します。\n" + \
121
+ f"2. コマンド実行に必要なパラメータのなかで、ユーザーのクエリから取得できないものは、コマンド定義にあるデフォルト値を指定して実行してください。\n" + \
122
+ f"3. もしエラーが発生した場合は、ユーザーにコマンド名とパラメータとエラー内容を提示してください。\n"
123
+
124
+ description = description if is_japan else \
125
+ f"Command offer registered in {self.ver.__appid__}."
126
+ instruction = instruction if is_japan else \
127
+ f"You are the expert who knows what the commands mean." + \
128
+ f"When a user wants to execute a command, you follow these steps to ensure that the command is executed.\n" + \
129
+ f"1. Identify the command you want to execute from the user's query.\n" + \
130
+ f"2. Any parameters required to execute the command that cannot be obtained from the user's query should be executed with the default values provided in the command definition.\n" + \
131
+ f"3. If an error occurs, provide the user with the command name, parameters, and error description.\n"
132
+
133
+ description = args.agent_description if args.agent_description else description
134
+ instruction = args.agent_instruction if args.agent_instruction else instruction
135
+ if logger.level == logging.DEBUG:
136
+ logger.debug(f"google-adk loading..")
137
+ from google.adk.agents import Agent
138
+ if logger.level == logging.DEBUG:
139
+ logger.debug(f"litellm loading..")
140
+ from google.adk.models.lite_llm import LiteLlm
141
+ # loggerの初期化
142
+ common.reset_logger("LiteLLM Proxy")
143
+ common.reset_logger("LiteLLM Router")
144
+ common.reset_logger("LiteLLM")
145
+ if args.llmprov == 'openai':
146
+ if args.llmmodel is None: raise ValueError("llmmodel is required.")
147
+ if args.llmapikey is None: raise ValueError("llmapikey is required.")
148
+ agent = Agent(
149
+ name=args.agent_name,
150
+ model=LiteLlm(
151
+ model=args.llmmodel,
152
+ api_key=args.llmapikey,
153
+ endpoint=args.llmendpoint,
154
+ ),
155
+ description=description,
156
+ instruction=instruction,
157
+ tools=tools,
158
+ )
159
+ elif args.llmprov == 'azureopenai':
160
+ if args.llmmodel is None: raise ValueError("llmmodel is required.")
161
+ if args.llmendpoint is None: raise ValueError("llmendpoint is required.")
162
+ if args.llmapikey is None: raise ValueError("llmapikey is required.")
163
+ if args.llmapiversion is None: raise ValueError("llmapiversion is required.")
164
+ agent = Agent(
165
+ name=args.agent_name,
166
+ model=LiteLlm(
167
+ model=args.llmmodel,
168
+ api_key=args.llmapikey,
169
+ endpoint=args.llmendpoint,
170
+ api_version=args.llmapiversion,
171
+ ),
172
+ description=description,
173
+ instruction=instruction,
174
+ tools=tools,
175
+ )
176
+ elif args.llmprov == 'vertexai':
177
+ if args.llmmodel is None: raise ValueError("llmmodel is required.")
178
+ if args.llmlocation is None: raise ValueError("llmlocation is required.")
179
+ if args.llmsvaccountfile is not None:
180
+ with open(args.llmsvaccountfile, "r", encoding="utf-8") as f:
181
+ vertex_credentials = json.load(f)
182
+ elif args.llmprojectid is None: raise ValueError("llmprojectid is required.")
183
+ agent = Agent(
184
+ name=args.agent_name,
185
+ model=LiteLlm(
186
+ model=args.llmmodel,
187
+ #vertex_project=args.llmprojectid,
188
+ vertex_credentials=vertex_credentials,
189
+ vertex_location=args.llmlocation,
190
+ #seed=args.llmseed,
191
+ #temperature=args.llmtemperature,
192
+ ),
193
+ description=description,
194
+ instruction=instruction,
195
+ tools=tools,
196
+ )
197
+ elif args.llmprov == 'ollama':
198
+ if args.llmmodel is None: raise ValueError("llmmodel is required.")
199
+ if args.llmendpoint is None: raise ValueError("llmendpoint is required.")
200
+ agent = Agent(
201
+ name=args.agent_name,
202
+ model=LiteLlm(
203
+ model=f"ollama/{args.llmmodel}",
204
+ api_base=args.llmendpoint,
205
+ temperature=args.llmtemperature,
206
+ stream=True
207
+ ),
208
+ description=description,
209
+ instruction=instruction,
210
+ tools=tools,
211
+ )
212
+ else:
213
+ raise ValueError("llmprov is required.")
214
+ if logger.level == logging.DEBUG:
215
+ logger.debug(f"create_agent complate.")
216
+ return agent
217
+
218
+ def create_runner(self, logger:logging.Logger, args:argparse.Namespace, session_service, agent) -> Any:
219
+ """
220
+ ランナーを作成します
221
+
222
+ Args:
223
+ logger (logging.Logger): ロガー
224
+ args (argparse.Namespace): 引数
225
+ session_service (BaseSessionService): セッションサービス
226
+ agent (Agent): エージェント
227
+
228
+ Returns:
229
+ Runner: ランナー
230
+ """
231
+ from google.adk.runners import Runner
232
+ return Runner(
233
+ app_name=self.ver.__appid__,
234
+ agent=agent,
235
+ session_service=session_service,
236
+ )
237
+
238
+ def init_agent_runner(self, logger:logging.Logger, args:argparse.Namespace) -> Tuple[Any, Any]:
239
+ """
240
+ エージェントの初期化を行います
241
+
242
+ Args:
243
+ logger (logging.Logger): ロガー
244
+ args (argparse.Namespace): 引数
245
+
246
+ Returns:
247
+ Tuple[Any, Any]: ランナーとFastMCP
248
+ """
249
+ if logger.level == logging.DEBUG:
250
+ logger.debug(f"init_agent_runner processing..")
251
+ # loggerの初期化
252
+ common.reset_logger("httpx")
253
+ common.reset_logger("google_adk.google.adk.sessions.database_session_service")
254
+ common.reset_logger("mcp.server.streamable_http_manager")
255
+ # モジュールインポート
256
+ from fastmcp import FastMCP
257
+ from google.adk.sessions import BaseSessionService
258
+ mcp:FastMCP = self.create_mcpserver(args)
259
+ session_service:BaseSessionService = self.create_session_service(args)
260
+ options = Options.getInstance()
261
+ tools:Callable[[logging.Logger, argparse.Namespace, float, Dict], Tuple[int, Dict[str, Any], Any]] = []
262
+
263
+ def _ds(d:str) -> str:
264
+ return f'"{d}"' if d is not None else 'None'
265
+ def _t2s(o:Dict[str, Any], req=True) -> str:
266
+ t, m, d, r = o["type"], o["multi"], o["default"], o["required"]
267
+ if t == Options.T_BOOL: return ("List[bool]=[]" if m else f"bool={d}") if req else ("List[bool]" if m else f"bool")
268
+ if t == Options.T_DATE: return ("List[str]=[]" if m else f"str={_ds(d)}") if req else ("List[str]" if m else f"str")
269
+ if t == Options.T_DATETIME: return ("List[str]=[]" if m else f"str={_ds(d)}") if req else ("List[str]" if m else f"str")
270
+ if t == Options.T_DICT: return ("List[dict]=[]" if m else f"dict={d}") if req else ("List[dict]" if m else f"dict")
271
+ if t == Options.T_DIR or t == Options.T_FILE:
272
+ if d is not None: d = str(d).replace('\\', '/')
273
+ return ("List[str]=[]" if m else f"str={_ds(d)}") if req else ("List[str]" if m else f"str")
274
+ if t == Options.T_FLOAT: return ("List[float]=[]" if m else f"float={d}") if req else ("List[float]" if m else f"float")
275
+ if t == Options.T_INT: return ("List[int]=[]" if m else f"int={d}") if req else ("List[int]" if m else f"int")
276
+ if t == Options.T_STR: return ("List[str]=[]" if m else f"str={_ds(d)}") if req else ("List[str]" if m else f"str")
277
+ if t == Options.T_TEXT: return ("List[str]=[]" if m else f"str={_ds(d)}") if req else ("List[str]" if m else f"str")
278
+ raise ValueError(f"Unknown type: {t} for option {o['opt']}")
279
+ def _arg(o:Dict[str, Any], is_japan) -> str:
280
+ t, d = o["type"], o["default"]
281
+ s = f' {o["opt"]}:'
282
+ if t == Options.T_DIR or t == Options.T_FILE:
283
+ d = str(d).replace("\\", "/")
284
+ s += f'{_t2s(o, False)}={d}:'
285
+ #s += f'Optional[{_t2s(o, False)}]={d}:'
286
+ s += f'{o["discription_ja"] if is_japan else o["discription_en"]}'
287
+ return s
288
+ def _coercion(a:argparse.Namespace, key:str, dval) -> str:
289
+ dval = f'opt["{key}"] if "{key}" in opt else ' + f'"{dval}"' if isinstance(dval, str) else dval
290
+ aval = args.__dict__[key] if hasattr(args, key) and args.__dict__[key] else None
291
+ aval = f'"{aval}"' if isinstance(aval, str) else aval
292
+ ret = f'opt["{key}"] = {aval}' if aval is not None else f'opt["{key}"] = {dval}'
293
+ return ret
294
+ language, _ = locale.getlocale()
295
+ is_japan = language.find('Japan') >= 0 or language.find('ja_JP') >= 0
296
+ for mode in options.get_mode_keys():
297
+ for cmd in options.get_cmd_keys(mode):
298
+ if not options.get_cmd_attr(mode, cmd, 'use_agent'):
299
+ continue
300
+ discription = options.get_cmd_attr(mode, cmd, 'discription_ja' if is_japan else 'discription_en')
301
+ choices = options.get_cmd_choices(mode, cmd, False)
302
+ if len([opt for opt in choices if 'opt' in opt and opt['opt'] == 'signin_file']) <= 0:
303
+ choices.append(dict(opt="signin_file", type=Options.T_FILE, default=f'.{self.ver.__appid__}/user_list.yml', required=True, multi=False, hide=True, choice=None,
304
+ discription_ja="サインイン可能なユーザーとパスワードを記載したファイルを指定します。省略した時は認証を要求しません。",
305
+ discription_en="Specify a file containing users and passwords with which they can signin. If omitted, no authentication is required."),)
306
+ fn = f"{mode}_{cmd}"
307
+ func_txt = f'def {fn}(' + ", ".join([f'{o["opt"]}:{_t2s(o, False)}' for o in choices]) + '):\n'
308
+ func_txt += f' """\n'
309
+ func_txt += f' {discription}\n'
310
+ func_txt += f' Args:\n'
311
+ func_txt += "\n".join([_arg(o, is_japan) for o in choices])
312
+ func_txt += f'\n'
313
+ func_txt += f' Returns:\n'
314
+ func_txt += f' Dict[str, Any]:{"処理結果" if is_japan else "Processing Result"}\n'
315
+ func_txt += f' """\n'
316
+ func_txt += f' scope = signin.get_request_scope()\n'
317
+ func_txt += f' logger = common.default_logger()\n'
318
+ func_txt += f' opt = dict()\n'
319
+ func_txt += f' opt["mode"] = "{mode}"\n'
320
+ func_txt += f' opt["cmd"] = "{cmd}"\n'
321
+ func_txt += f' opt["data"] = opt["data"] if hasattr(opt, "data") else common.HOME_DIR / ".{self.ver.__appid__}"\n'
322
+ func_txt += f' opt["format"] = False\n'
323
+ func_txt += f' opt["output_json"] = None\n'
324
+ func_txt += f' opt["output_json_append"] = False\n'
325
+ func_txt += f' opt["debug"] = logger.level == logging.DEBUG\n'
326
+ func_txt += '\n'.join([f' opt["{o["opt"]}"] = {o["opt"]}' for o in choices])+'\n'
327
+ func_txt += f' {_coercion(args, "host", self.default_host)}\n'
328
+ func_txt += f' {_coercion(args, "port", self.default_port)}\n'
329
+ func_txt += f' {_coercion(args, "password", self.default_pass)}\n'
330
+ func_txt += f' {_coercion(args, "svname", self.default_svname)}\n'
331
+ func_txt += f' {_coercion(args, "retry_count", 3)}\n'
332
+ func_txt += f' {_coercion(args, "retry_interval", 3)}\n'
333
+ func_txt += f' {_coercion(args, "timeout", 15)}\n'
334
+ func_txt += f' {_coercion(args, "output_json", None)}\n'
335
+ func_txt += f' {_coercion(args, "output_json_append", False)}\n'
336
+ func_txt += f' {_coercion(args, "stdout_log", False)}\n'
337
+ func_txt += f' {_coercion(args, "capture_stdout", False)}\n'
338
+ func_txt += f' {_coercion(args, "capture_maxsize", 1024*1024)}\n'
339
+ func_txt += f' {_coercion(args, "tag", None)}\n'
340
+ func_txt += f' {_coercion(args, "clmsg_id", None)}\n'
341
+ func_txt += f' opt["signin_file"] = signin_file if signin_file else ".{self.ver.__appid__}/user_list.yml"\n'
342
+ func_txt += f' args = argparse.Namespace(**opt)\n'
343
+ func_txt += f' signin_data = signin.Signin.load_signin_file(args.signin_file)\n'
344
+ func_txt += f' req = scope["req"] if scope["req"] is not None else scope["websocket"]\n'
345
+ func_txt += f' sign = signin.Signin._check_signin(req, scope["res"], signin_data, logger)\n'
346
+ func_txt += f' if sign is not None:\n'
347
+ func_txt += f' logger.warning("Unable to execute command because authentication information cannot be obtained")\n'
348
+ func_txt += f' return dict(warn="Unable to execute command because authentication information cannot be obtained")\n'
349
+ func_txt += f' groups = req.session["signin"]["groups"]\n'
350
+ func_txt += f' logger.info("Call agent tool `{mode}_{cmd}`:user="+str(req.session["signin"]["name"])+" groups="+str(groups)+" args="+str(args))\n'
351
+ func_txt += f' if not signin.Signin._check_cmd(signin_data, groups, "{mode}", "{cmd}", logger):\n'
352
+ func_txt += f' logger.warning("You do not have permission to execute this command.")\n'
353
+ func_txt += f' return dict(warn="You do not have permission to execute this command.")\n'
354
+ func_txt += f' feat = Options.getInstance().get_cmd_attr("{mode}", "{cmd}", "feature")\n'
355
+ func_txt += f' try:\n'
356
+ func_txt += f' st, ret, _ = feat.apprun(logger, args, time.perf_counter(), [])\n'
357
+ func_txt += f' return ret\n'
358
+ func_txt += f' except Exception as e:\n'
359
+ func_txt += f' logger.error("Error occurs when tool is executed:", exc_info=True)\n'
360
+ func_txt += f' raise e\n'
361
+ func_txt += f'tools.append({fn})\n'
362
+ if logger.level == logging.DEBUG:
363
+ logger.debug(f"generating agent tool: {fn}")
364
+
365
+ exec(func_txt,
366
+ dict(time=time,List=List, argparse=argparse, common=common, Options=Options, logging=logging, signin=signin,),
367
+ dict(tools=tools, mcp=mcp))
368
+ exec(f"@mcp.tool\n{func_txt}",
369
+ dict(time=time,List=List, argparse=argparse, common=common, Options=Options, logging=logging, signin=signin,),
370
+ dict(tools=[], mcp=mcp))
371
+ root_agent = self.create_agent(logger, args, tools)
372
+ runner = self.create_runner(logger, args, session_service, root_agent)
373
+ if logger.level == logging.DEBUG:
374
+ logger.debug(f"init_agent_runner complate.")
375
+ return runner, mcp
cmdbox/app/options.py CHANGED
@@ -832,11 +832,13 @@ class Options:
832
832
  if hasattr(arg, 'redis_password'): opt['password'] = arg.redis_password
833
833
  if hasattr(arg, 'svname'): opt['svname'] = arg.svname
834
834
  if hasattr(arg, 'clmsg_id'): opt['clmsg_id'] = arg.clmsg_id
835
+ if hasattr(arg, 'client_only'): opt['client_only'] = arg.client_only
835
836
  elif isinstance(arg, web.Web):
836
837
  opt['host'] = arg.redis_host
837
838
  opt['port'] = arg.redis_port
838
839
  opt['password'] = arg.redis_password
839
840
  opt['svname'] = arg.svname
841
+ opt['client_only'] = arg.client_only
840
842
  elif isinstance(arg, feature.Feature):
841
843
  func_feature = arg
842
844
  opt['clmsg_src'] = func_feature.__class__.__name__
cmdbox/app/web.py CHANGED
@@ -1,5 +1,4 @@
1
1
  from cmdbox.app import common, options
2
- from cmdbox.app.auth import signin, signin_saml
3
2
  from cmdbox.app.commons import module
4
3
  from fastapi import FastAPI, Request, Response
5
4
  from pathlib import Path
@@ -12,6 +11,7 @@ import copy
12
11
  import ctypes
13
12
  import datetime
14
13
  import gevent
14
+ import jwt
15
15
  import logging
16
16
  import multiprocessing
17
17
  import os
@@ -120,7 +120,8 @@ class Web:
120
120
  self.cb_queue = queue.Queue(1000)
121
121
  self.options = options.Options.getInstance()
122
122
  self.webcap_client = requests.Session()
123
- signin_file_data = signin.Signin.load_signin_file(self.signin_file)
123
+ from cmdbox.app.auth import signin, signin_saml
124
+ signin_file_data = signin.Signin.load_signin_file(self.signin_file, self=self)
124
125
  self.signin = signin.Signin(self.logger, self.signin_file, signin_file_data, self.appcls, self.ver)
125
126
  self.signin_saml = signin_saml.SigninSAML(self.logger, self.signin_file, signin_file_data, self.appcls, self.ver)
126
127
 
@@ -247,7 +248,25 @@ class Web:
247
248
  for u in copy.deepcopy(signin_data['users']):
248
249
  u['password'] = '********'
249
250
  if 'apikeys' in u:
250
- u['apikeys'] = dict([(ak, '********') for ak in u['apikeys']])
251
+ for an, ak in u['apikeys'].items():
252
+ exp = '-'
253
+ try:
254
+ cls = self.signin.__class__
255
+ publickey = None
256
+ if cls.verify_jwt_certificate is not None:
257
+ publickey = cls.verify_jwt_certificate.public_key()
258
+ if publickey is None and cls.verify_jwt_publickey is not None:
259
+ publickey = cls.verify_jwt_publickey
260
+ t = jwt.decode(ak, publickey, algorithms=[cls.verify_jwt_algorithm],
261
+ issuer=cls.verify_jwt_issuer, audience=cls.verify_jwt_audience,
262
+ options={'verify_iss': cls.verify_jwt_issuer is not None,
263
+ 'verify_aud': cls.verify_jwt_audience is not None})
264
+ exp = datetime.datetime.fromtimestamp(t['exp']).strftime('%Y-%m-%d %H:%M:%S')
265
+ u['apikeys'][an] = (ak, exp, '-')
266
+ except jwt.exceptions.InvalidTokenError as e:
267
+ u['apikeys'][an] = (ak, '-', str(e))
268
+ except Exception as e:
269
+ u['apikeys'][an] = (ak, '-', '-')
251
270
  if u['name'] == name:
252
271
  return [u]
253
272
  signin_last = self.user_data(None, u['uid'], u['name'], 'signin', 'last_update')
@@ -289,10 +308,19 @@ class Web:
289
308
  if user['apikey_name'] in u['apikeys']:
290
309
  raise ValueError(f"ApiKey name is already exists. ({user})")
291
310
  apikey = common.random_string(64)
292
- u['apikeys'][user['apikey_name']] = common.hash_password(apikey, 'sha1')
311
+ u['apikeys'][user['apikey_name']] = apikey
312
+ if signin_data['apikey']['gen_jwt']['enabled']:
313
+ cls = self.signin.__class__
314
+ claims = cls.gen_jwt_claims.copy() if cls.gen_jwt_claims is not None else dict()
315
+ claims['exp'] = int(time.time()) + int(claims.get('exp', 3600))
316
+ claims['uid'] = u['uid']
317
+ claims['name'] = u['name']
318
+ claims['groups'] = u['groups']
319
+ claims['email'] = u['email']
320
+ claims['apikey_name'] = user['apikey_name']
321
+ apikey = jwt.encode(claims, cls.gen_jwt_privatekey, algorithm=cls.gen_jwt_algorithm)
322
+ u['apikeys'][user['apikey_name']] = apikey
293
323
 
294
- if self.signin_file is None:
295
- raise ValueError(f"signin_file is None.")
296
324
  if self.logger.level == logging.DEBUG:
297
325
  self.logger.debug(f"apikey_add: {user} -> {self.signin_file}")
298
326
  common.save_yml(self.signin_file, signin_data)
cmdbox/autoload.py ADDED
@@ -0,0 +1,10 @@
1
+ from pathlib import Path
2
+ import os
3
+ import sys
4
+
5
+ if __name__ == "__main__":
6
+ os.chdir(Path(__file__).resolve().parent.parent)
7
+ sys.path.insert(0, "")
8
+ from cmdbox.app import app
9
+ exit_code = app.main(webcall=True)
10
+ exit(exit_code)
@@ -74,7 +74,7 @@ pathrule: # List of RESTAPI rules, rules that determine whe
74
74
  - groups: [user]
75
75
  paths: [/signin, /assets, /bbforce_cmd, /copyright, /dosignin, /dosignout, /password/change,
76
76
  /gui/user_data/load, /gui/user_data/save, /gui/user_data/delete,
77
- /agent, /mcp,
77
+ /agent, /mcpsv,
78
78
  /exec_cmd, /exec_pipe, /filer, /result, /gui, /get_server_opt, /usesignout, /versions_cmdbox, /versions_used]
79
79
  rule: allow
80
80
  - groups: [readonly]
@@ -102,6 +102,30 @@ password: # Password settings.
102
102
  enabled: true # Specify whether or not to enable account lockout.
103
103
  threshold: 5 # Specify the number of failed login attempts before the account is locked.
104
104
  reset: 30 # Specify the number of minutes after which the failed login count will be reset.
105
+ apikey:
106
+ gen_cert: # Specify whether to generate a certificate for API key.
107
+ enabled: true # Specify whether to enable certificate generation for API key.
108
+ privatekey: idp_private.pem # Specify the destination file for the generated private key.
109
+ certificate: idp_cert.pem # Specify the destination file for the generated certificate.
110
+ publickey: idp_public.pem # Specify the destination file for the generated public key.
111
+ gen_jwt: # Specify whether to generate JWT for API key.
112
+ enabled: true # Specify whether to enable JWT generation for API key.
113
+ privatekey: idp_private.pem # Specify the private key file for JWT generation.
114
+ privatekey_passphrase: # Specify the passphrase for the private key file.
115
+ # If the private key is encrypted, specify the passphrase here.
116
+ algorithm: RS256 # Specify the algorithm used to generate the JWT. The value can be RS256, PS256, or ES256.
117
+ claims: # Specify the claims to be included in the JWT.
118
+ iss: identity_provider # Specify the issuer of the JWT. This is usually the name of the identity provider.
119
+ sub: app_user # Specify the subject of the JWT. This is usually the name of the application.
120
+ aud: app_organization # Specify the audience of the JWT. This is usually the name of the organization that will use the application.
121
+ exp: 31536000 # Specify the expiration time of the JWT in seconds. The default is 31536000 seconds (1 year).
122
+ verify_jwt: # Specify whether to verify JWT for API key.
123
+ enabled: true # Specify whether to enable JWT verification for API key.
124
+ certificate: idp_cert.pem # Specify the certificate file for JWT verification.
125
+ publickey: idp_public.pem # Specify the public key file for JWT verification. Not required if certificate exists.
126
+ issuer: identity_provider # Specify the issuer of the JWT. This is usually the name of the identity provider. (If not specified, no verification)
127
+ audience: app_organization # Specify the audience of the JWT. This is usually the name of the organization that will use the application. (If not specified, no verification)
128
+ algorithm: RS256 # Specify the algorithm used to verify the JWT. The value can be RS256, PS256, or ES256.
105
129
  oauth2: # OAuth2 settings.
106
130
  providers: # This is a per-provider setting for OAuth2.
107
131
  google: # Google's OAuth2 configuration.
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2017 Laurent LAPORTE
3
+ Copyright (c) 2015-2022 José Padilla
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
18
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
19
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
20
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
21
+ SOFTWARE.
@@ -0,0 +1,73 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 Alex Grönholm
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+
23
+ This project contains code copied from the Python standard library.
24
+ The following is the required license notice for those parts.
25
+
26
+ PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
27
+ --------------------------------------------
28
+
29
+ 1. This LICENSE AGREEMENT is between the Python Software Foundation
30
+ ("PSF"), and the Individual or Organization ("Licensee") accessing and
31
+ otherwise using this software ("Python") in source or binary form and
32
+ its associated documentation.
33
+
34
+ 2. Subject to the terms and conditions of this License Agreement, PSF hereby
35
+ grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
36
+ analyze, test, perform and/or display publicly, prepare derivative works,
37
+ distribute, and otherwise use Python alone or in any derivative version,
38
+ provided, however, that PSF's License Agreement and PSF's notice of copyright,
39
+ i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
40
+ 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022 Python Software Foundation;
41
+ All Rights Reserved" are retained in Python alone or in any derivative version
42
+ prepared by Licensee.
43
+
44
+ 3. In the event Licensee prepares a derivative work that is based on
45
+ or incorporates Python or any part thereof, and wants to make
46
+ the derivative work available to others as provided herein, then
47
+ Licensee hereby agrees to include in any such work a brief summary of
48
+ the changes made to Python.
49
+
50
+ 4. PSF is making Python available to Licensee on an "AS IS"
51
+ basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
52
+ IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
53
+ DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
54
+ FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
55
+ INFRINGE ANY THIRD PARTY RIGHTS.
56
+
57
+ 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
58
+ FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
59
+ A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
60
+ OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
61
+
62
+ 6. This License Agreement will automatically terminate upon a material
63
+ breach of its terms and conditions.
64
+
65
+ 7. Nothing in this License Agreement shall be deemed to create any
66
+ relationship of agency, partnership, or joint venture between PSF and
67
+ Licensee. This License Agreement does not grant permission to use PSF
68
+ trademarks or trade name in a trademark sense to endorse or promote
69
+ products or services of Licensee, or any third party.
70
+
71
+ 8. By copying, installing or otherwise using Python, Licensee
72
+ agrees to be bound by the terms and conditions of this License
73
+ Agreement.