Wire hermit_getenv across the engine, rebrand WebUI/systemd/docs, and add apps/desktop (Tauri 2 + React) with a DeepSeek-Harness-like UI. Qt app/ is frozen; full libcstcore FFI is scaffolded behind --features engine. Co-authored-by: Cursor <cursoragent@cursor.com>
96 lines
3.0 KiB
C
96 lines
3.0 KiB
C
#include "cst_ext.h"
|
|
#include "cst_hermit_glyph.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#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");
|
|
}
|