controlmesh 0.17.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (444) hide show
  1. controlmesh/_Dockerfile.sandbox +48 -0
  2. controlmesh/__init__.py +3 -0
  3. controlmesh/__main__.py +474 -0
  4. controlmesh/_banner.txt +14 -0
  5. controlmesh/_config_example.json +238 -0
  6. controlmesh/_home_defaults/RULES.md +74 -0
  7. controlmesh/_home_defaults/config/RULES-all-clis.md +185 -0
  8. controlmesh/_home_defaults/config/RULES-claude-only.md +133 -0
  9. controlmesh/_home_defaults/config/RULES-codex-only.md +141 -0
  10. controlmesh/_home_defaults/config/RULES-gemini-only.md +139 -0
  11. controlmesh/_home_defaults/workspace/JOIN_NOTIFICATION.md +9 -0
  12. controlmesh/_home_defaults/workspace/RULES.md +91 -0
  13. controlmesh/_home_defaults/workspace/cron_tasks/RULES-all-clis.md +153 -0
  14. controlmesh/_home_defaults/workspace/cron_tasks/RULES-claude-only.md +88 -0
  15. controlmesh/_home_defaults/workspace/cron_tasks/RULES-codex-only.md +111 -0
  16. controlmesh/_home_defaults/workspace/cron_tasks/RULES-gemini-only.md +100 -0
  17. controlmesh/_home_defaults/workspace/memory_system/MAINMEMORY.md +13 -0
  18. controlmesh/_home_defaults/workspace/memory_system/RULES.md +51 -0
  19. controlmesh/_home_defaults/workspace/output_to_user/RULES.md +20 -0
  20. controlmesh/_home_defaults/workspace/skills/RULES.md +44 -0
  21. controlmesh/_home_defaults/workspace/skills/skill-creator/LICENSE.txt +202 -0
  22. controlmesh/_home_defaults/workspace/skills/skill-creator/SKILL.md +357 -0
  23. controlmesh/_home_defaults/workspace/skills/skill-creator/references/output-patterns.md +82 -0
  24. controlmesh/_home_defaults/workspace/skills/skill-creator/references/workflows.md +28 -0
  25. controlmesh/_home_defaults/workspace/skills/skill-creator/scripts/init_skill.py +304 -0
  26. controlmesh/_home_defaults/workspace/skills/skill-creator/scripts/package_skill.py +111 -0
  27. controlmesh/_home_defaults/workspace/skills/skill-creator/scripts/quick_validate.py +107 -0
  28. controlmesh/_home_defaults/workspace/tasks/RULES.md +21 -0
  29. controlmesh/_home_defaults/workspace/telegram_files/RULES.md +43 -0
  30. controlmesh/_home_defaults/workspace/tools/RULES.md +48 -0
  31. controlmesh/_home_defaults/workspace/tools/_tool_shared.py +71 -0
  32. controlmesh/_home_defaults/workspace/tools/agent_tools/RULES.md +249 -0
  33. controlmesh/_home_defaults/workspace/tools/agent_tools/ask_agent.py +83 -0
  34. controlmesh/_home_defaults/workspace/tools/agent_tools/ask_agent_async.py +114 -0
  35. controlmesh/_home_defaults/workspace/tools/agent_tools/create_agent.py +391 -0
  36. controlmesh/_home_defaults/workspace/tools/agent_tools/edit_shared_knowledge.py +84 -0
  37. controlmesh/_home_defaults/workspace/tools/agent_tools/list_agents.py +72 -0
  38. controlmesh/_home_defaults/workspace/tools/agent_tools/remove_agent.py +70 -0
  39. controlmesh/_home_defaults/workspace/tools/cron_tools/RULES-all-clis.md +156 -0
  40. controlmesh/_home_defaults/workspace/tools/cron_tools/RULES-claude-only.md +106 -0
  41. controlmesh/_home_defaults/workspace/tools/cron_tools/RULES-codex-only.md +118 -0
  42. controlmesh/_home_defaults/workspace/tools/cron_tools/RULES-gemini-only.md +109 -0
  43. controlmesh/_home_defaults/workspace/tools/cron_tools/_shared.py +233 -0
  44. controlmesh/_home_defaults/workspace/tools/cron_tools/cron_add.py +455 -0
  45. controlmesh/_home_defaults/workspace/tools/cron_tools/cron_edit.py +500 -0
  46. controlmesh/_home_defaults/workspace/tools/cron_tools/cron_list.py +83 -0
  47. controlmesh/_home_defaults/workspace/tools/cron_tools/cron_remove.py +153 -0
  48. controlmesh/_home_defaults/workspace/tools/cron_tools/cron_time.py +103 -0
  49. controlmesh/_home_defaults/workspace/tools/media_tools/RULES.md +35 -0
  50. controlmesh/_home_defaults/workspace/tools/media_tools/file_info.py +99 -0
  51. controlmesh/_home_defaults/workspace/tools/media_tools/list_files.py +93 -0
  52. controlmesh/_home_defaults/workspace/tools/media_tools/process_video.py +278 -0
  53. controlmesh/_home_defaults/workspace/tools/media_tools/read_document.py +115 -0
  54. controlmesh/_home_defaults/workspace/tools/media_tools/transcribe_audio.py +156 -0
  55. controlmesh/_home_defaults/workspace/tools/task_tools/RULES.md +93 -0
  56. controlmesh/_home_defaults/workspace/tools/task_tools/_shared.py +72 -0
  57. controlmesh/_home_defaults/workspace/tools/task_tools/ask_parent.py +66 -0
  58. controlmesh/_home_defaults/workspace/tools/task_tools/cancel_task.py +53 -0
  59. controlmesh/_home_defaults/workspace/tools/task_tools/create_task.py +114 -0
  60. controlmesh/_home_defaults/workspace/tools/task_tools/delete_task.py +54 -0
  61. controlmesh/_home_defaults/workspace/tools/task_tools/list_tasks.py +63 -0
  62. controlmesh/_home_defaults/workspace/tools/task_tools/resume_task.py +67 -0
  63. controlmesh/_home_defaults/workspace/tools/user_tools/RULES.md +31 -0
  64. controlmesh/_home_defaults/workspace/tools/webhook_tools/RULES-all-clis.md +318 -0
  65. controlmesh/_home_defaults/workspace/tools/webhook_tools/RULES-claude-only.md +236 -0
  66. controlmesh/_home_defaults/workspace/tools/webhook_tools/RULES-codex-only.md +258 -0
  67. controlmesh/_home_defaults/workspace/tools/webhook_tools/RULES-gemini-only.md +244 -0
  68. controlmesh/_home_defaults/workspace/tools/webhook_tools/_shared.py +61 -0
  69. controlmesh/_home_defaults/workspace/tools/webhook_tools/webhook_add.py +442 -0
  70. controlmesh/_home_defaults/workspace/tools/webhook_tools/webhook_edit.py +282 -0
  71. controlmesh/_home_defaults/workspace/tools/webhook_tools/webhook_list.py +73 -0
  72. controlmesh/_home_defaults/workspace/tools/webhook_tools/webhook_remove.py +83 -0
  73. controlmesh/_home_defaults/workspace/tools/webhook_tools/webhook_rotate_token.py +124 -0
  74. controlmesh/_home_defaults/workspace/tools/webhook_tools/webhook_test.py +195 -0
  75. controlmesh/_plugins/__init__.py +1 -0
  76. controlmesh/_plugins/feishu_auth_kit/VENDORED_FROM.md +13 -0
  77. controlmesh/_plugins/feishu_auth_kit/__init__.py +4 -0
  78. controlmesh/_plugins/feishu_auth_kit/feishu_auth_kit/__init__.py +161 -0
  79. controlmesh/_plugins/feishu_auth_kit/feishu_auth_kit/agent_runtime.py +397 -0
  80. controlmesh/_plugins/feishu_auth_kit/feishu_auth_kit/app_registration.py +220 -0
  81. controlmesh/_plugins/feishu_auth_kit/feishu_auth_kit/cardkit.py +127 -0
  82. controlmesh/_plugins/feishu_auth_kit/feishu_auth_kit/claude_adapter.py +57 -0
  83. controlmesh/_plugins/feishu_auth_kit/feishu_auth_kit/cli.py +1289 -0
  84. controlmesh/_plugins/feishu_auth_kit/feishu_auth_kit/client.py +155 -0
  85. controlmesh/_plugins/feishu_auth_kit/feishu_auth_kit/device_flow.py +127 -0
  86. controlmesh/_plugins/feishu_auth_kit/feishu_auth_kit/domains.py +83 -0
  87. controlmesh/_plugins/feishu_auth_kit/feishu_auth_kit/message_context.py +162 -0
  88. controlmesh/_plugins/feishu_auth_kit/feishu_auth_kit/models.py +48 -0
  89. controlmesh/_plugins/feishu_auth_kit/feishu_auth_kit/native_agent_tools.py +166 -0
  90. controlmesh/_plugins/feishu_auth_kit/feishu_auth_kit/native_contract.py +259 -0
  91. controlmesh/_plugins/feishu_auth_kit/feishu_auth_kit/orchestration.py +447 -0
  92. controlmesh/_plugins/feishu_auth_kit/feishu_auth_kit/owner_policy.py +111 -0
  93. controlmesh/_plugins/feishu_auth_kit/feishu_auth_kit/probe.py +52 -0
  94. controlmesh/_plugins/feishu_auth_kit/feishu_auth_kit/runtime_cards.py +219 -0
  95. controlmesh/_plugins/feishu_auth_kit/feishu_auth_kit/scopes.py +127 -0
  96. controlmesh/_plugins/feishu_auth_kit/feishu_auth_kit/token_store.py +147 -0
  97. controlmesh/_plugins/feishu_auth_kit/runner.py +10 -0
  98. controlmesh/agents_runtime/__init__.py +12 -0
  99. controlmesh/agents_runtime/context.py +32 -0
  100. controlmesh/agents_runtime/manager.py +116 -0
  101. controlmesh/agents_runtime/progress.py +166 -0
  102. controlmesh/agents_runtime/results.py +59 -0
  103. controlmesh/agents_runtime/tools.py +166 -0
  104. controlmesh/api/__init__.py +24 -0
  105. controlmesh/api/admin_read.py +214 -0
  106. controlmesh/api/catalog_http.py +63 -0
  107. controlmesh/api/crypto.py +50 -0
  108. controlmesh/api/server.py +665 -0
  109. controlmesh/background/__init__.py +8 -0
  110. controlmesh/background/models.py +55 -0
  111. controlmesh/background/observer.py +279 -0
  112. controlmesh/bus/__init__.py +16 -0
  113. controlmesh/bus/adapters.py +303 -0
  114. controlmesh/bus/bus.py +221 -0
  115. controlmesh/bus/cron_sanitize.py +27 -0
  116. controlmesh/bus/envelope.py +90 -0
  117. controlmesh/bus/lock_pool.py +59 -0
  118. controlmesh/case_pack/__init__.py +15 -0
  119. controlmesh/case_pack/__main__.py +58 -0
  120. controlmesh/case_pack/io.py +14 -0
  121. controlmesh/case_pack/lint.py +192 -0
  122. controlmesh/case_pack/models.py +93 -0
  123. controlmesh/case_pack/render.py +93 -0
  124. controlmesh/cleanup/__init__.py +5 -0
  125. controlmesh/cleanup/observer.py +149 -0
  126. controlmesh/cli/__init__.py +33 -0
  127. controlmesh/cli/auth.py +432 -0
  128. controlmesh/cli/base.py +228 -0
  129. controlmesh/cli/claude_provider.py +219 -0
  130. controlmesh/cli/coalescer.py +149 -0
  131. controlmesh/cli/codex_cache.py +126 -0
  132. controlmesh/cli/codex_cache_observer.py +36 -0
  133. controlmesh/cli/codex_discovery.py +149 -0
  134. controlmesh/cli/codex_events.py +315 -0
  135. controlmesh/cli/codex_hooks.py +230 -0
  136. controlmesh/cli/codex_provider.py +293 -0
  137. controlmesh/cli/executor.py +336 -0
  138. controlmesh/cli/factory.py +32 -0
  139. controlmesh/cli/gemini_cache.py +61 -0
  140. controlmesh/cli/gemini_cache_observer.py +54 -0
  141. controlmesh/cli/gemini_events.py +215 -0
  142. controlmesh/cli/gemini_provider.py +659 -0
  143. controlmesh/cli/gemini_utils.py +455 -0
  144. controlmesh/cli/init_wizard.py +810 -0
  145. controlmesh/cli/model_cache.py +259 -0
  146. controlmesh/cli/openai_agents_provider.py +349 -0
  147. controlmesh/cli/param_resolver.py +137 -0
  148. controlmesh/cli/process_registry.py +257 -0
  149. controlmesh/cli/service.py +406 -0
  150. controlmesh/cli/stream_events.py +196 -0
  151. controlmesh/cli/timeout_controller.py +223 -0
  152. controlmesh/cli/types.py +78 -0
  153. controlmesh/cli_commands/__init__.py +1 -0
  154. controlmesh/cli_commands/agents.py +318 -0
  155. controlmesh/cli_commands/api_cmd.py +170 -0
  156. controlmesh/cli_commands/auth.py +1357 -0
  157. controlmesh/cli_commands/docker.py +515 -0
  158. controlmesh/cli_commands/feishu.py +93 -0
  159. controlmesh/cli_commands/install.py +91 -0
  160. controlmesh/cli_commands/lifecycle.py +288 -0
  161. controlmesh/cli_commands/runtime.py +212 -0
  162. controlmesh/cli_commands/service.py +92 -0
  163. controlmesh/cli_commands/status.py +214 -0
  164. controlmesh/cli_commands/tasks.py +137 -0
  165. controlmesh/commands.py +52 -0
  166. controlmesh/config.py +605 -0
  167. controlmesh/config_reload.py +226 -0
  168. controlmesh/cron/__init__.py +6 -0
  169. controlmesh/cron/dependency_queue.py +163 -0
  170. controlmesh/cron/execution.py +298 -0
  171. controlmesh/cron/manager.py +207 -0
  172. controlmesh/cron/observer.py +412 -0
  173. controlmesh/cron/policy.py +119 -0
  174. controlmesh/errors.py +37 -0
  175. controlmesh/files/__init__.py +1 -0
  176. controlmesh/files/allowed_roots.py +27 -0
  177. controlmesh/files/browser.py +28 -0
  178. controlmesh/files/image_processor.py +76 -0
  179. controlmesh/files/prompt.py +64 -0
  180. controlmesh/files/storage.py +86 -0
  181. controlmesh/files/tags.py +157 -0
  182. controlmesh/gateways/__init__.py +9 -0
  183. controlmesh/gateways/config.py +95 -0
  184. controlmesh/gateways/types.py +8 -0
  185. controlmesh/heartbeat/__init__.py +5 -0
  186. controlmesh/heartbeat/observer.py +346 -0
  187. controlmesh/history/__init__.py +6 -0
  188. controlmesh/history/catalog.py +325 -0
  189. controlmesh/history/index.py +1341 -0
  190. controlmesh/history/models.py +39 -0
  191. controlmesh/history/store.py +52 -0
  192. controlmesh/i18n/__init__.py +82 -0
  193. controlmesh/i18n/de/chat.toml +459 -0
  194. controlmesh/i18n/de/cli.toml +286 -0
  195. controlmesh/i18n/de/commands.toml +29 -0
  196. controlmesh/i18n/de/wizard.toml +182 -0
  197. controlmesh/i18n/en/chat.toml +458 -0
  198. controlmesh/i18n/en/cli.toml +286 -0
  199. controlmesh/i18n/en/commands.toml +29 -0
  200. controlmesh/i18n/en/wizard.toml +182 -0
  201. controlmesh/i18n/es/chat.toml +459 -0
  202. controlmesh/i18n/es/cli.toml +286 -0
  203. controlmesh/i18n/es/commands.toml +29 -0
  204. controlmesh/i18n/es/wizard.toml +182 -0
  205. controlmesh/i18n/fr/chat.toml +459 -0
  206. controlmesh/i18n/fr/cli.toml +286 -0
  207. controlmesh/i18n/fr/commands.toml +29 -0
  208. controlmesh/i18n/fr/wizard.toml +182 -0
  209. controlmesh/i18n/loader.py +131 -0
  210. controlmesh/i18n/nl/chat.toml +459 -0
  211. controlmesh/i18n/nl/cli.toml +286 -0
  212. controlmesh/i18n/nl/commands.toml +29 -0
  213. controlmesh/i18n/nl/wizard.toml +182 -0
  214. controlmesh/i18n/pt/chat.toml +459 -0
  215. controlmesh/i18n/pt/cli.toml +286 -0
  216. controlmesh/i18n/pt/commands.toml +29 -0
  217. controlmesh/i18n/pt/wizard.toml +182 -0
  218. controlmesh/i18n/ru/chat.toml +459 -0
  219. controlmesh/i18n/ru/cli.toml +286 -0
  220. controlmesh/i18n/ru/commands.toml +29 -0
  221. controlmesh/i18n/ru/wizard.toml +182 -0
  222. controlmesh/infra/__init__.py +22 -0
  223. controlmesh/infra/atomic_io.py +51 -0
  224. controlmesh/infra/base_observer.py +55 -0
  225. controlmesh/infra/base_task_observer.py +68 -0
  226. controlmesh/infra/boot_id.py +83 -0
  227. controlmesh/infra/docker.py +460 -0
  228. controlmesh/infra/docker_extras.py +292 -0
  229. controlmesh/infra/env_secrets.py +109 -0
  230. controlmesh/infra/file_watcher.py +73 -0
  231. controlmesh/infra/fs.py +57 -0
  232. controlmesh/infra/inflight.py +113 -0
  233. controlmesh/infra/install.py +99 -0
  234. controlmesh/infra/json_store.py +33 -0
  235. controlmesh/infra/pidlock.py +145 -0
  236. controlmesh/infra/platform.py +17 -0
  237. controlmesh/infra/process_tree.py +231 -0
  238. controlmesh/infra/recovery.py +104 -0
  239. controlmesh/infra/restart.py +63 -0
  240. controlmesh/infra/service.py +65 -0
  241. controlmesh/infra/service_base.py +122 -0
  242. controlmesh/infra/service_linux.py +258 -0
  243. controlmesh/infra/service_logs.py +101 -0
  244. controlmesh/infra/service_macos.py +238 -0
  245. controlmesh/infra/service_windows.py +309 -0
  246. controlmesh/infra/startup_state.py +89 -0
  247. controlmesh/infra/task_runner.py +132 -0
  248. controlmesh/infra/updater.py +450 -0
  249. controlmesh/infra/version.py +186 -0
  250. controlmesh/integrations/__init__.py +2 -0
  251. controlmesh/integrations/feishu_auth_kit.py +139 -0
  252. controlmesh/log_context.py +69 -0
  253. controlmesh/logging_config.py +137 -0
  254. controlmesh/memory/__init__.py +80 -0
  255. controlmesh/memory/commands.py +94 -0
  256. controlmesh/memory/dreaming.py +435 -0
  257. controlmesh/memory/models.py +167 -0
  258. controlmesh/memory/promotion.py +195 -0
  259. controlmesh/memory/search.py +245 -0
  260. controlmesh/memory/store.py +97 -0
  261. controlmesh/messenger/__init__.py +28 -0
  262. controlmesh/messenger/callback_router.py +98 -0
  263. controlmesh/messenger/capabilities.py +48 -0
  264. controlmesh/messenger/commands.py +67 -0
  265. controlmesh/messenger/feishu/__init__.py +6 -0
  266. controlmesh/messenger/feishu/auth/__init__.py +84 -0
  267. controlmesh/messenger/feishu/auth/app_info.py +173 -0
  268. controlmesh/messenger/feishu/auth/auth_cards.py +107 -0
  269. controlmesh/messenger/feishu/auth/brand.py +93 -0
  270. controlmesh/messenger/feishu/auth/card_auth.py +148 -0
  271. controlmesh/messenger/feishu/auth/card_auth_context.py +38 -0
  272. controlmesh/messenger/feishu/auth/card_auth_runner.py +266 -0
  273. controlmesh/messenger/feishu/auth/device_flow.py +168 -0
  274. controlmesh/messenger/feishu/auth/errors.py +92 -0
  275. controlmesh/messenger/feishu/auth/feishu_card_sender.py +62 -0
  276. controlmesh/messenger/feishu/auth/native_auth_all_runner.py +239 -0
  277. controlmesh/messenger/feishu/auth/orchestration_runner.py +458 -0
  278. controlmesh/messenger/feishu/auth/runtime_auth.py +148 -0
  279. controlmesh/messenger/feishu/auth/runtime_continuation.py +80 -0
  280. controlmesh/messenger/feishu/auth/token_store.py +86 -0
  281. controlmesh/messenger/feishu/auth/uat_client.py +164 -0
  282. controlmesh/messenger/feishu/bot.py +1834 -0
  283. controlmesh/messenger/feishu/bundled_runtime.py +84 -0
  284. controlmesh/messenger/feishu/card_stream.py +440 -0
  285. controlmesh/messenger/feishu/id_map.py +100 -0
  286. controlmesh/messenger/feishu/inbound.py +105 -0
  287. controlmesh/messenger/feishu/long_connection.py +317 -0
  288. controlmesh/messenger/feishu/media.py +311 -0
  289. controlmesh/messenger/feishu/media_meta.py +143 -0
  290. controlmesh/messenger/feishu/message_context.py +304 -0
  291. controlmesh/messenger/feishu/native_tools/__init__.py +29 -0
  292. controlmesh/messenger/feishu/native_tools/agent_runtime.py +23 -0
  293. controlmesh/messenger/feishu/native_tools/client.py +67 -0
  294. controlmesh/messenger/feishu/native_tools/executor.py +518 -0
  295. controlmesh/messenger/feishu/progress_preview.py +171 -0
  296. controlmesh/messenger/feishu/sender.py +111 -0
  297. controlmesh/messenger/feishu/settings_card.py +492 -0
  298. controlmesh/messenger/feishu/startup.py +53 -0
  299. controlmesh/messenger/feishu/tool_auth.py +147 -0
  300. controlmesh/messenger/feishu/transport.py +177 -0
  301. controlmesh/messenger/matrix/__init__.py +1 -0
  302. controlmesh/messenger/matrix/bot.py +1174 -0
  303. controlmesh/messenger/matrix/buttons.py +142 -0
  304. controlmesh/messenger/matrix/credentials.py +103 -0
  305. controlmesh/messenger/matrix/file_browser.py +113 -0
  306. controlmesh/messenger/matrix/formatting.py +126 -0
  307. controlmesh/messenger/matrix/id_map.py +69 -0
  308. controlmesh/messenger/matrix/media.py +189 -0
  309. controlmesh/messenger/matrix/sender.py +230 -0
  310. controlmesh/messenger/matrix/startup.py +83 -0
  311. controlmesh/messenger/matrix/streaming.py +109 -0
  312. controlmesh/messenger/matrix/transport.py +256 -0
  313. controlmesh/messenger/matrix/typing.py +64 -0
  314. controlmesh/messenger/multi.py +163 -0
  315. controlmesh/messenger/notifications.py +41 -0
  316. controlmesh/messenger/protocol.py +72 -0
  317. controlmesh/messenger/registry.py +127 -0
  318. controlmesh/messenger/send_opts.py +14 -0
  319. controlmesh/messenger/telegram/__init__.py +1 -0
  320. controlmesh/messenger/telegram/abort.py +92 -0
  321. controlmesh/messenger/telegram/app.py +1600 -0
  322. controlmesh/messenger/telegram/buttons.py +140 -0
  323. controlmesh/messenger/telegram/callbacks.py +120 -0
  324. controlmesh/messenger/telegram/chat_tracker.py +135 -0
  325. controlmesh/messenger/telegram/controlmesh_images/logo_text.png +0 -0
  326. controlmesh/messenger/telegram/controlmesh_images/welcome.png +0 -0
  327. controlmesh/messenger/telegram/dedup.py +78 -0
  328. controlmesh/messenger/telegram/edit_streaming.py +422 -0
  329. controlmesh/messenger/telegram/file_browser.py +123 -0
  330. controlmesh/messenger/telegram/formatting.py +209 -0
  331. controlmesh/messenger/telegram/handlers.py +205 -0
  332. controlmesh/messenger/telegram/media.py +265 -0
  333. controlmesh/messenger/telegram/message_dispatch.py +241 -0
  334. controlmesh/messenger/telegram/middleware.py +416 -0
  335. controlmesh/messenger/telegram/sender.py +294 -0
  336. controlmesh/messenger/telegram/startup.py +149 -0
  337. controlmesh/messenger/telegram/streaming.py +170 -0
  338. controlmesh/messenger/telegram/topic.py +101 -0
  339. controlmesh/messenger/telegram/transport.py +328 -0
  340. controlmesh/messenger/telegram/typing.py +56 -0
  341. controlmesh/messenger/telegram/upgrade_handler.py +212 -0
  342. controlmesh/messenger/telegram/welcome.py +142 -0
  343. controlmesh/messenger/weixin/__init__.py +25 -0
  344. controlmesh/messenger/weixin/api.py +191 -0
  345. controlmesh/messenger/weixin/auth_state.py +41 -0
  346. controlmesh/messenger/weixin/auth_store.py +239 -0
  347. controlmesh/messenger/weixin/bot.py +300 -0
  348. controlmesh/messenger/weixin/id_map.py +61 -0
  349. controlmesh/messenger/weixin/runtime.py +227 -0
  350. controlmesh/messenger/weixin/runtime_state.py +99 -0
  351. controlmesh/messenger/weixin/transport.py +31 -0
  352. controlmesh/multiagent/__init__.py +8 -0
  353. controlmesh/multiagent/bus.py +446 -0
  354. controlmesh/multiagent/commands.py +111 -0
  355. controlmesh/multiagent/health.py +55 -0
  356. controlmesh/multiagent/internal_api.py +540 -0
  357. controlmesh/multiagent/models.py +101 -0
  358. controlmesh/multiagent/registry.py +109 -0
  359. controlmesh/multiagent/shared_knowledge.py +129 -0
  360. controlmesh/multiagent/stack.py +74 -0
  361. controlmesh/multiagent/supervisor.py +676 -0
  362. controlmesh/orchestrator/__init__.py +6 -0
  363. controlmesh/orchestrator/commands.py +816 -0
  364. controlmesh/orchestrator/core.py +1021 -0
  365. controlmesh/orchestrator/directives.py +65 -0
  366. controlmesh/orchestrator/flows.py +896 -0
  367. controlmesh/orchestrator/hooks.py +115 -0
  368. controlmesh/orchestrator/injection.py +273 -0
  369. controlmesh/orchestrator/lifecycle.py +207 -0
  370. controlmesh/orchestrator/observers.py +230 -0
  371. controlmesh/orchestrator/providers.py +221 -0
  372. controlmesh/orchestrator/registry.py +82 -0
  373. controlmesh/orchestrator/selectors/__init__.py +1 -0
  374. controlmesh/orchestrator/selectors/agent_router.py +50 -0
  375. controlmesh/orchestrator/selectors/capability_registry.py +232 -0
  376. controlmesh/orchestrator/selectors/cron_selector.py +222 -0
  377. controlmesh/orchestrator/selectors/model_selector.py +431 -0
  378. controlmesh/orchestrator/selectors/models.py +28 -0
  379. controlmesh/orchestrator/selectors/session_selector.py +157 -0
  380. controlmesh/orchestrator/selectors/settings_selector.py +438 -0
  381. controlmesh/orchestrator/selectors/task_selector.py +253 -0
  382. controlmesh/orchestrator/selectors/utils.py +14 -0
  383. controlmesh/run.py +86 -0
  384. controlmesh/runtime/__init__.py +6 -0
  385. controlmesh/runtime/models.py +27 -0
  386. controlmesh/runtime/store.py +52 -0
  387. controlmesh/security/__init__.py +11 -0
  388. controlmesh/security/content.py +98 -0
  389. controlmesh/security/paths.py +52 -0
  390. controlmesh/session/__init__.py +8 -0
  391. controlmesh/session/key.py +81 -0
  392. controlmesh/session/manager.py +735 -0
  393. controlmesh/session/named.py +391 -0
  394. controlmesh/tasks/__init__.py +1 -0
  395. controlmesh/tasks/hub.py +645 -0
  396. controlmesh/tasks/models.py +135 -0
  397. controlmesh/tasks/registry.py +269 -0
  398. controlmesh/tasks/task_policy.py +169 -0
  399. controlmesh/team/__init__.py +45 -0
  400. controlmesh/team/api.py +279 -0
  401. controlmesh/team/contracts.py +399 -0
  402. controlmesh/team/execution.py +2054 -0
  403. controlmesh/team/live.py +479 -0
  404. controlmesh/team/models.py +1428 -0
  405. controlmesh/team/orchestrator.py +31 -0
  406. controlmesh/team/phases.py +88 -0
  407. controlmesh/team/presentation.py +61 -0
  408. controlmesh/team/runtime_attachment.py +408 -0
  409. controlmesh/team/runtime_control.py +502 -0
  410. controlmesh/team/state/__init__.py +5 -0
  411. controlmesh/team/state/base.py +52 -0
  412. controlmesh/team/state/dispatch.py +123 -0
  413. controlmesh/team/state/events.py +65 -0
  414. controlmesh/team/state/mailbox.py +92 -0
  415. controlmesh/team/state/manifest.py +29 -0
  416. controlmesh/team/state/phase.py +29 -0
  417. controlmesh/team/state/recovery.py +111 -0
  418. controlmesh/team/state/runtime.py +307 -0
  419. controlmesh/team/state/snapshot.py +224 -0
  420. controlmesh/team/state/store.py +318 -0
  421. controlmesh/team/state/tasks.py +180 -0
  422. controlmesh/text/__init__.py +0 -0
  423. controlmesh/text/response_format.py +168 -0
  424. controlmesh/text/tool_event_format.py +54 -0
  425. controlmesh/utils/__init__.py +0 -0
  426. controlmesh/utils/quiet_hours.py +42 -0
  427. controlmesh/webhook/__init__.py +6 -0
  428. controlmesh/webhook/auth.py +172 -0
  429. controlmesh/webhook/manager.py +100 -0
  430. controlmesh/webhook/models.py +143 -0
  431. controlmesh/webhook/observer.py +308 -0
  432. controlmesh/webhook/server.py +171 -0
  433. controlmesh/workspace/__init__.py +43 -0
  434. controlmesh/workspace/cron_tasks.py +234 -0
  435. controlmesh/workspace/init.py +577 -0
  436. controlmesh/workspace/loader.py +26 -0
  437. controlmesh/workspace/paths.py +270 -0
  438. controlmesh/workspace/rules_selector.py +279 -0
  439. controlmesh/workspace/skill_sync.py +430 -0
  440. controlmesh-0.17.0.dist-info/METADATA +354 -0
  441. controlmesh-0.17.0.dist-info/RECORD +444 -0
  442. controlmesh-0.17.0.dist-info/WHEEL +4 -0
  443. controlmesh-0.17.0.dist-info/entry_points.txt +2 -0
  444. controlmesh-0.17.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,48 @@
1
+ # Dockerfile.sandbox -- lightweight sandbox for controlmesh CLI execution.
2
+ # Based on Node 22 (Debian bookworm) with Python 3, Claude Code CLI,
3
+ # and Codex CLI pre-installed. The container runs "sleep infinity" so
4
+ # controlmesh can `docker exec` into it on demand.
5
+
6
+ FROM node:22-bookworm-slim
7
+
8
+ ENV DEBIAN_FRONTEND=noninteractive \
9
+ LANG=en_US.UTF-8 \
10
+ LC_ALL=en_US.UTF-8 \
11
+ PIP_BREAK_SYSTEM_PACKAGES=1
12
+
13
+ # System packages: Python, build tools, Git, locale support
14
+ RUN apt-get update \
15
+ && apt-get install -y --no-install-recommends \
16
+ python3 python3-pip python3-venv python3-dev \
17
+ build-essential git curl ca-certificates sudo locales \
18
+ && sed -i '/en_US.UTF-8/s/^# //' /etc/locale.gen && locale-gen \
19
+ && rm -rf /var/lib/apt/lists/*
20
+
21
+ # Chrome/Chromium runtime dependencies for browser-based skills
22
+ # (e.g. patchright, playwright). Only shared libraries -- no browser binary.
23
+ RUN apt-get update \
24
+ && apt-get install -y --no-install-recommends \
25
+ libasound2 libatk-bridge2.0-0 libatk1.0-0 libcairo2 libcups2 \
26
+ libdbus-1-3 libdrm2 libexpat1 libgbm1 libglib2.0-0 libnspr4 \
27
+ libnss3 libpango-1.0-0 libx11-6 libx11-xcb1 libxcb1 \
28
+ libxcomposite1 libxdamage1 libxext6 libxfixes3 libxkbcommon0 \
29
+ libxrandr2 libxshmfence1 \
30
+ fonts-liberation fonts-noto-color-emoji \
31
+ && rm -rf /var/lib/apt/lists/*
32
+
33
+ # Allow pip installs without the "externally managed" guard
34
+ RUN rm -f /usr/lib/python*/EXTERNALLY-MANAGED
35
+
36
+ # Install Claude Code CLI and Codex CLI
37
+ RUN npm install -g @anthropic-ai/claude-code @openai/codex @google/gemini-cli
38
+
39
+ # Prepare a writable data directory
40
+ RUN mkdir -p /data && chown node:node /data
41
+
42
+ # Let the `node` user run sudo without a password (useful for apt inside sandbox)
43
+ RUN echo "node ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/node
44
+
45
+ USER node
46
+ WORKDIR /workspace
47
+
48
+ CMD ["sleep", "infinity"]
@@ -0,0 +1,3 @@
1
+ """ControlMesh public package and CLI entrypoint surface."""
2
+
3
+ __version__ = "0.17.0"
@@ -0,0 +1,474 @@
1
+ """Entry point: python -m controlmesh."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import json
7
+ import logging
8
+ import os
9
+ import shutil
10
+ import signal
11
+ import sys
12
+ from collections.abc import Callable
13
+ from pathlib import Path
14
+
15
+ from rich.console import Console
16
+
17
+ # Re-exports from cli_commands — referenced by main() dispatch and by
18
+ # tests that patch controlmesh.__main__.<name>.
19
+ from controlmesh.cli_commands.agents import cmd_agents as _cmd_agents
20
+ from controlmesh.cli_commands.api_cmd import cmd_api as _cmd_api
21
+ from controlmesh.cli_commands.auth import cmd_auth as _cmd_auth
22
+ from controlmesh.cli_commands.docker import cmd_docker as _cmd_docker
23
+ from controlmesh.cli_commands.feishu import cmd_feishu as _cmd_feishu
24
+ from controlmesh.cli_commands.install import cmd_install as _cmd_install
25
+ from controlmesh.cli_commands.lifecycle import (
26
+ cmd_restart as _cmd_restart,
27
+ )
28
+ from controlmesh.cli_commands.lifecycle import (
29
+ start_bot as _start_bot,
30
+ )
31
+ from controlmesh.cli_commands.lifecycle import (
32
+ stop_bot as _stop_bot,
33
+ )
34
+ from controlmesh.cli_commands.lifecycle import (
35
+ uninstall as _uninstall,
36
+ )
37
+ from controlmesh.cli_commands.lifecycle import (
38
+ upgrade as _upgrade,
39
+ )
40
+ from controlmesh.cli_commands.runtime import cmd_runtime as _cmd_runtime
41
+ from controlmesh.cli_commands.service import cmd_service as _cmd_service
42
+ from controlmesh.cli_commands.status import (
43
+ print_status as _print_status,
44
+ )
45
+ from controlmesh.cli_commands.status import (
46
+ print_usage as _print_usage,
47
+ )
48
+ from controlmesh.cli_commands.tasks import cmd_tasks as _cmd_tasks
49
+ from controlmesh.config import (
50
+ DEFAULT_EMPTY_GEMINI_API_KEY,
51
+ AgentConfig,
52
+ deep_merge_config,
53
+ )
54
+ from controlmesh.i18n import t_rich
55
+ from controlmesh.infra.json_store import atomic_json_save
56
+ from controlmesh.infra.version import get_current_version
57
+ from controlmesh.workspace.init import init_workspace
58
+ from controlmesh.workspace.paths import resolve_paths
59
+
60
+ logger = logging.getLogger(__name__)
61
+
62
+ _console = Console()
63
+
64
+
65
+ # ---------------------------------------------------------------------------
66
+ # Config helpers
67
+ # ---------------------------------------------------------------------------
68
+
69
+
70
+ def _is_configured() -> bool:
71
+ """Check if bot has a valid configuration."""
72
+ paths = resolve_paths()
73
+ if not paths.config_path.exists():
74
+ return False
75
+ try:
76
+ data = json.loads(paths.config_path.read_text(encoding="utf-8"))
77
+ except (json.JSONDecodeError, OSError):
78
+ return False
79
+
80
+ transports = data.get("transports", [])
81
+ if not transports:
82
+ transports = [data.get("transport", "telegram")]
83
+ for t in transports:
84
+ checker = _IS_CONFIGURED_CHECKS.get(t, _is_configured_telegram)
85
+ if not checker(data):
86
+ return False
87
+ return True
88
+
89
+
90
+ def _is_configured_telegram(data: dict[str, object]) -> bool:
91
+ token = data.get("telegram_token", "")
92
+ users = data.get("allowed_user_ids", [])
93
+ return bool(token) and not str(token).startswith("YOUR_") and bool(users)
94
+
95
+
96
+ def _is_configured_matrix(data: dict[str, object]) -> bool:
97
+ mx = data.get("matrix", {})
98
+ if not isinstance(mx, dict):
99
+ return False
100
+ return bool(mx.get("homeserver")) and bool(mx.get("user_id"))
101
+
102
+
103
+ def _is_configured_feishu(data: dict[str, object]) -> bool:
104
+ fs = data.get("feishu", {})
105
+ if not isinstance(fs, dict):
106
+ return False
107
+ return (
108
+ fs.get("mode", "bot_only") == "bot_only"
109
+ and fs.get("brand", "feishu") == "feishu"
110
+ and bool(fs.get("app_id"))
111
+ and bool(fs.get("app_secret"))
112
+ )
113
+
114
+
115
+ def _is_configured_weixin(data: dict[str, object]) -> bool:
116
+ wx = data.get("weixin", {})
117
+ if not isinstance(wx, dict):
118
+ return False
119
+ if wx.get("mode", "ilink") != "ilink":
120
+ return False
121
+ if not bool(wx.get("enabled", False)):
122
+ return False
123
+
124
+ raw_home = data.get("controlmesh_home") or os.environ.get(
125
+ "CONTROLMESH_HOME",
126
+ "~/.controlmesh",
127
+ )
128
+ controlmesh_home = Path(str(raw_home)).expanduser()
129
+ relative_path = str(wx.get("credentials_path", "weixin_store/credentials.json"))
130
+ from controlmesh.messenger.weixin.auth_store import WeixinCredentialStore
131
+
132
+ return (
133
+ WeixinCredentialStore(controlmesh_home, relative_path=relative_path).load_credentials()
134
+ is not None
135
+ )
136
+
137
+
138
+ _IS_CONFIGURED_CHECKS: dict[str, Callable[[dict[str, object]], bool]] = {
139
+ "telegram": _is_configured_telegram,
140
+ "matrix": _is_configured_matrix,
141
+ "feishu": _is_configured_feishu,
142
+ "weixin": _is_configured_weixin,
143
+ }
144
+
145
+
146
+ def load_config() -> AgentConfig:
147
+ """Load, auto-create, and smart-merge the bot config.
148
+
149
+ Resolution order:
150
+ 1. ``~/.controlmesh/config/config.json`` (canonical location)
151
+ 2. Copy from ``config.example.json`` in the framework root on first start
152
+ 3. Fall back to Pydantic defaults if example file is missing
153
+
154
+ On every load the config is deep-merged with current Pydantic defaults
155
+ so that new fields from framework updates are added without destroying
156
+ user settings.
157
+ """
158
+ paths = resolve_paths()
159
+ config_path = paths.config_path
160
+
161
+ first_start = not config_path.exists()
162
+
163
+ if first_start:
164
+ config_path.parent.mkdir(parents=True, exist_ok=True)
165
+ example = paths.config_example_path
166
+ if example.is_file():
167
+ shutil.copy2(example, config_path)
168
+ logger.info("Created config from config.example.json at %s", config_path)
169
+ else:
170
+ defaults = AgentConfig().model_dump(mode="json")
171
+ defaults["gemini_api_key"] = DEFAULT_EMPTY_GEMINI_API_KEY
172
+ defaults.pop("api", None) # Beta: only written by `controlmesh api enable`
173
+ atomic_json_save(config_path, defaults)
174
+ logger.info("Created default config at %s", config_path)
175
+
176
+ try:
177
+ user_data: dict[str, object] = json.loads(config_path.read_text(encoding="utf-8"))
178
+ except (json.JSONDecodeError, OSError):
179
+ logger.exception("Failed to parse config at %s", config_path)
180
+ sys.exit(1)
181
+
182
+ normalized_existing = False
183
+ if user_data.get("gemini_api_key") is None:
184
+ user_data["gemini_api_key"] = DEFAULT_EMPTY_GEMINI_API_KEY
185
+ normalized_existing = True
186
+
187
+ defaults = AgentConfig().model_dump(mode="json")
188
+ defaults["gemini_api_key"] = DEFAULT_EMPTY_GEMINI_API_KEY
189
+ defaults.pop("api", None) # Beta: only written by `controlmesh api enable`
190
+ merged, changed = deep_merge_config(user_data, defaults)
191
+ changed = changed or normalized_existing
192
+ configured_home = user_data.get("controlmesh_home")
193
+ default_home = defaults.get("controlmesh_home")
194
+ env_selected_home = os.environ.get("CONTROLMESH_HOME")
195
+ if not configured_home or (env_selected_home and configured_home == default_home):
196
+ resolved_home = str(paths.controlmesh_home)
197
+ if merged.get("controlmesh_home") != resolved_home:
198
+ merged["controlmesh_home"] = resolved_home
199
+ changed = True
200
+
201
+ if changed:
202
+ atomic_json_save(config_path, merged)
203
+ logger.info("Extended config with new default fields")
204
+
205
+ init_workspace(paths)
206
+ return AgentConfig.model_validate(merged)
207
+
208
+
209
+ # ---------------------------------------------------------------------------
210
+ # Bot lifecycle
211
+ # ---------------------------------------------------------------------------
212
+
213
+
214
+ def _validate_transports(config: AgentConfig) -> None:
215
+ """Run transport-specific config validators for all active transports."""
216
+ for t in config.transports:
217
+ validator = _TRANSPORT_VALIDATORS.get(t)
218
+ if validator:
219
+ validator(config)
220
+
221
+
222
+ async def run_bot(config: AgentConfig) -> int:
223
+ """Validate config and run the bot via AgentSupervisor.
224
+
225
+ The supervisor manages the main agent and dynamically created sub-agents
226
+ from ``agents.json``. If no sub-agents are defined, the supervisor runs
227
+ only the main agent — behaviour is identical to the old single-bot path.
228
+
229
+ Returns the exit code from the bot (``0`` = clean, ``42`` = restart requested).
230
+ """
231
+ paths = resolve_paths(controlmesh_home=config.controlmesh_home)
232
+ _validate_transports(config)
233
+
234
+ from controlmesh.infra.pidlock import acquire_lock, release_lock
235
+ from controlmesh.multiagent.supervisor import AgentSupervisor
236
+
237
+ acquire_lock(pid_file=paths.controlmesh_home / "bot.pid", kill_existing=True)
238
+
239
+ supervisor = AgentSupervisor(config)
240
+ exit_code = 0
241
+ loop = asyncio.get_running_loop()
242
+ current_task = asyncio.current_task()
243
+ installed_signals: list[signal.Signals] = []
244
+
245
+ def _request_shutdown() -> None:
246
+ if current_task is not None and not current_task.done():
247
+ current_task.cancel()
248
+
249
+ if current_task is not None and sys.platform != "win32":
250
+ for sig in (signal.SIGTERM, signal.SIGINT):
251
+ try:
252
+ loop.add_signal_handler(sig, _request_shutdown)
253
+ except (NotImplementedError, RuntimeError, ValueError):
254
+ continue
255
+ installed_signals.append(sig)
256
+
257
+ try:
258
+ exit_code = await supervisor.start()
259
+ except asyncio.CancelledError:
260
+ logger.info("Termination signal received, shutting down gracefully...")
261
+ except KeyboardInterrupt:
262
+ logger.info("Shutting down...")
263
+ finally:
264
+ for sig in installed_signals:
265
+ loop.remove_signal_handler(sig)
266
+ await supervisor.stop_all()
267
+ release_lock(pid_file=paths.controlmesh_home / "bot.pid")
268
+ return exit_code
269
+
270
+
271
+ # Backward-compat alias for external scripts that call run_telegram().
272
+ run_telegram = run_bot
273
+
274
+
275
+ def _validate_telegram_config(config: AgentConfig) -> None:
276
+ """Validate Telegram transport requirements."""
277
+ missing_token = not config.telegram_token or config.telegram_token.startswith("YOUR_")
278
+ needs_users = not config.allowed_user_ids
279
+ if missing_token or needs_users:
280
+ _console.print(t_rich("config.incomplete"))
281
+ sys.exit(1)
282
+
283
+
284
+ def _validate_matrix_config(config: AgentConfig) -> None:
285
+ """Validate Matrix transport requirements."""
286
+ m = config.matrix
287
+ hint = t_rich("config.onboarding_hint")
288
+ if not m.homeserver:
289
+ _console.print(t_rich("config.matrix_no_homeserver", hint=hint))
290
+ sys.exit(1)
291
+ if not m.user_id:
292
+ _console.print(t_rich("config.matrix_no_user", hint=hint))
293
+ sys.exit(1)
294
+ if not m.password and not m.access_token:
295
+ _console.print(t_rich("config.matrix_no_auth", hint=hint))
296
+ sys.exit(1)
297
+ if not m.allowed_rooms and not m.allowed_users:
298
+ _console.print(t_rich("config.matrix_no_target", hint=hint))
299
+ sys.exit(1)
300
+
301
+
302
+ def _validate_feishu_config(config: AgentConfig) -> None:
303
+ """Validate Feishu bot-only transport requirements."""
304
+ fs = config.feishu
305
+ if fs.mode != "bot_only":
306
+ _console.print("Feishu cut 1 supports only feishu.mode='bot_only'.")
307
+ sys.exit(1)
308
+ if fs.brand != "feishu":
309
+ _console.print("Feishu cut 1 supports only feishu.brand='feishu'.")
310
+ sys.exit(1)
311
+ if not fs.app_id:
312
+ _console.print("Feishu transport requires an existing Feishu self-built app.")
313
+ _console.print("Missing field: feishu.app_id.")
314
+ _console.print("Run `controlmesh auth feishu setup` for zero-app onboarding guidance.")
315
+ sys.exit(1)
316
+ if not fs.app_secret:
317
+ _console.print("Feishu transport requires an existing Feishu self-built app.")
318
+ _console.print("Missing field: feishu.app_secret.")
319
+ _console.print("Run `controlmesh auth feishu setup` for zero-app onboarding guidance.")
320
+ sys.exit(1)
321
+
322
+
323
+ def _validate_weixin_config(config: AgentConfig) -> None:
324
+ """Validate Weixin iLink transport requirements."""
325
+ wx = config.weixin
326
+ if wx.mode != "ilink":
327
+ _console.print("Weixin cut 1 supports only weixin.mode='ilink'.")
328
+ sys.exit(1)
329
+ if not wx.enabled:
330
+ _console.print("Weixin iLink transport is disabled by default; set weixin.enabled=true.")
331
+ sys.exit(1)
332
+
333
+ from controlmesh.messenger.weixin.auth_store import WeixinCredentialStore
334
+
335
+ store = WeixinCredentialStore(config.controlmesh_home, relative_path=wx.credentials_path)
336
+ if store.load_credentials() is None:
337
+ _console.print(f"Weixin iLink transport requires stored QR credentials at {store.path}.")
338
+ sys.exit(1)
339
+
340
+
341
+ _TRANSPORT_VALIDATORS: dict[str, Callable[[AgentConfig], None]] = {
342
+ "telegram": _validate_telegram_config,
343
+ "matrix": _validate_matrix_config,
344
+ "feishu": _validate_feishu_config,
345
+ "weixin": _validate_weixin_config,
346
+ }
347
+
348
+
349
+ # ---------------------------------------------------------------------------
350
+ # CLI command handlers
351
+ # ---------------------------------------------------------------------------
352
+
353
+
354
+ def _cmd_status() -> None:
355
+ """Show bot status or hint to configure."""
356
+ from rich.panel import Panel
357
+
358
+ _console.print()
359
+ if _is_configured():
360
+ _print_status()
361
+ else:
362
+ _console.print(
363
+ Panel(
364
+ t_rich("status.not_configured"),
365
+ title="[bold]Status[/bold]",
366
+ border_style="yellow",
367
+ padding=(1, 2),
368
+ ),
369
+ )
370
+ _console.print()
371
+
372
+
373
+ def _cmd_setup(verbose: bool) -> None:
374
+ """Run onboarding (with smart reset if already configured), then start."""
375
+ from controlmesh.cli.init_wizard import run_onboarding, run_smart_reset
376
+
377
+ _stop_bot()
378
+ paths = resolve_paths()
379
+ if _is_configured():
380
+ run_smart_reset(paths.controlmesh_home)
381
+ service_installed = run_onboarding()
382
+ if service_installed:
383
+ return
384
+ _start_bot(verbose)
385
+
386
+
387
+ def _default_action(verbose: bool) -> None:
388
+ """Auto-onboarding if unconfigured, then start bot."""
389
+ if not _is_configured():
390
+ from controlmesh.cli.init_wizard import run_onboarding
391
+
392
+ service_installed = run_onboarding()
393
+ if service_installed:
394
+ return
395
+ _start_bot(verbose)
396
+
397
+
398
+ def _print_version() -> None:
399
+ """Print the installed ControlMesh version."""
400
+ _console.print(get_current_version())
401
+
402
+
403
+ # ---------------------------------------------------------------------------
404
+ # Entry point
405
+ # ---------------------------------------------------------------------------
406
+
407
+ _COMMANDS: dict[str, str] = {
408
+ "help": "help",
409
+ "status": "status",
410
+ "stop": "stop",
411
+ "restart": "restart",
412
+ "upgrade": "upgrade",
413
+ "uninstall": "uninstall",
414
+ "onboarding": "setup",
415
+ "reset": "setup",
416
+ "service": "service",
417
+ "docker": "docker",
418
+ "api": "api",
419
+ "agents": "agents",
420
+ "install": "install",
421
+ "auth": "auth",
422
+ "runtime": "runtime",
423
+ "tasks": "tasks",
424
+ "feishu": "feishu",
425
+ }
426
+
427
+ _Action = Callable[[], None]
428
+
429
+
430
+ def main() -> None:
431
+ """CLI entry point."""
432
+ args = sys.argv[1:]
433
+ commands = [a for a in args if not a.startswith("-")]
434
+ verbose = "--verbose" in args
435
+ show_version = "--version" in args or ("-v" in args and not commands and not verbose)
436
+
437
+ if "--help" in args or "-h" in args:
438
+ commands.append("help")
439
+
440
+ if show_version:
441
+ _print_version()
442
+ return
443
+
444
+ # Resolve first matching command
445
+ action = next((_COMMANDS[c] for c in commands if c in _COMMANDS), None)
446
+
447
+ dispatch: dict[str, _Action] = {
448
+ "help": _print_usage,
449
+ "status": _cmd_status,
450
+ "stop": _stop_bot,
451
+ "restart": _cmd_restart,
452
+ "upgrade": _upgrade,
453
+ "uninstall": _uninstall,
454
+ "setup": lambda: _cmd_setup(verbose),
455
+ "service": lambda: _cmd_service(args),
456
+ "docker": lambda: _cmd_docker(args),
457
+ "api": lambda: _cmd_api(args),
458
+ "agents": lambda: _cmd_agents(args),
459
+ "install": lambda: _cmd_install(args),
460
+ "auth": lambda: _cmd_auth(args),
461
+ "runtime": lambda: _cmd_runtime(args),
462
+ "tasks": lambda: _cmd_tasks(args),
463
+ "feishu": lambda: _cmd_feishu(args),
464
+ }
465
+
466
+ handler = dispatch.get(action) if action else None
467
+ if handler is not None:
468
+ handler()
469
+ else:
470
+ _default_action(verbose)
471
+
472
+
473
+ if __name__ == "__main__":
474
+ main()
@@ -0,0 +1,14 @@
1
+ ██████╗ ██╗ ██╗ ██████╗████████╗ ██████╗ ██████╗ ██████╗ ███████╗██╗ ██╗
2
+ ██╔══██╗██║ ██║██╔════╝╚══██╔══╝██╔═══██╗██╔══██╗ ██╔══██╗██╔════╝██║ ██║
3
+ ██║ ██║██║ ██║██║ ██║ ██║ ██║██████╔╝ ██║ ██║█████╗ ██║ ██║
4
+ ██║ ██║██║ ██║██║ ██║ ██║ ██║██╔══██╗ ██║ ██║██╔══╝ ╚██╗ ██╔╝
5
+ ██████╔╝╚██████╔╝╚██████╗ ██║ ╚██████╔╝██║ ██║██╗██████╔╝███████╗ ╚████╔╝
6
+ ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝╚═════╝ ╚══════╝ ╚═══╝
7
+
8
+ ████████╗███████╗██╗ ███████╗ ██████╗ ██████╗ █████╗ ███╗ ███╗ ██████╗ ██████╗ ████████╗
9
+ ╚══██╔══╝██╔════╝██║ ██╔════╝██╔════╝ ██╔══██╗██╔══██╗████╗ ████║ ██╔══██╗██╔═══██╗╚══██╔══╝
10
+ ██║ █████╗ ██║ █████╗ ██║ ███╗██████╔╝███████║██╔████╔██║ ██████╔╝██║ ██║ ██║
11
+ ██║ ██╔══╝ ██║ ██╔══╝ ██║ ██║██╔══██╗██╔══██║██║╚██╔╝██║ ██╔══██╗██║ ██║ ██║
12
+ ██║ ███████╗███████╗███████╗╚██████╔╝██║ ██║██║ ██║██║ ╚═╝ ██║ ██████╔╝╚██████╔╝ ██║
13
+ ╚═╝ ╚══════╝╚══════╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝
14
+