#include "cst_ext.h" #include "cst_hermit_glyph.h" #include #include #include #include "cst_mcp.h" #include "cst_plugins.h" #include "cst_skills.h" #include "cst_subagent.h" #include "cst_tools.h" #include "cst_util.h" static char g_report[256]; const char *cst_extensions_report(void) { return g_report; } void cst_extensions_wait(FILE *log) { int ready = 0, total = 0; cst_mcp_counts(&ready, &total); if (total == 0) return; /* Default 8s (was 30s); override with CST_MCP_WAIT_MS. */ const char *e = hermit_getenv("MCP_WAIT_MS"); int ms = e && atoi(e) >= 0 ? atoi(e) : 8000; if (ms > 60000) ms = 60000; cst_mcp_wait_ready(ms); cst_mcp_info_t info[CST_MCP_MAX]; int n = cst_mcp_info(info, CST_MCP_MAX); for (int i = 0; log && i < n; i++) { if (info[i].state == CST_MCP_READY) fprintf(log, "mcp %s: %d tool%s\n", info[i].name, info[i].ntools, info[i].ntools == 1 ? "" : "s"); else if (info[i].state != CST_MCP_OFF) fprintf(log, "mcp %s: %s\n", info[i].name, info[i].error[0] ? info[i].error : "not ready"); } } void cst_extensions_load(const cst_agent_config_t *cfg, char *report, size_t report_sz) { if (report && report_sz) report[0] = 0; g_report[0] = 0; if (!cfg || cfg->tool_profile == CST_TOOLS_MINIMAL) return; const char *ws = cfg->workspace_root; int trusted = cst_settings_trusted(ws); int mcp_untrusted = 0, plugin_untrusted = 0; /* workspace and user mcp.json come before plugin servers: first name wins */ cst_mcp_load_configs(ws, trusted, &mcp_untrusted); int np = cst_plugins_load(ws, trusted, &plugin_untrusted); cst_skill_t *v = calloc(CST_SKILLS_MAX, sizeof(*v)); int ns = v ? cst_skills_list(ws, v, CST_SKILLS_MAX) : 0; free(v); if (ns > 0) cst_skills_register_tool(); if (cfg->depth == 0) cst_subagent_register_tool(ws); cst_mcp_start_all(ws); cst_buf_t b = {0}; if (ns > 0) cst_buf_printf(&b, "%d skill%s", ns, ns == 1 ? "" : "s"); if (np > 0) { cst_plugin_info_t info[CST_PLUGINS_MAX]; int n = cst_plugins_info(info, CST_PLUGINS_MAX), nt = 0; for (int i = 0; i < n; i++) nt += info[i].ntools; cst_buf_printf(&b, "%s%d plugin%s (%d tool%s)", b.len ? " · " : "", np, np == 1 ? "" : "s", nt, nt == 1 ? "" : "s"); } int ready = 0, total = 0; cst_mcp_counts(&ready, &total); if (total > 0) cst_buf_printf(&b, "%s%d MCP server%s", b.len ? " · " : "", total, total == 1 ? "" : "s"); if (mcp_untrusted + plugin_untrusted > 0) cst_buf_printf(&b, "%suntrusted workspace: /plugins trust", b.len ? " · " : ""); if (report && report_sz) snprintf(report, report_sz, "%s", b.buf ? b.buf : ""); snprintf(g_report, sizeof(g_report), "%s", b.buf ? b.buf : ""); cst_buf_free(&b); } void cst_extensions_unload(void) { cst_mcp_stop_all(); cst_plugins_unload(); cst_tool_unregister_owner("builtin:skills"); cst_tool_unregister_owner("builtin:task"); }