MCPcopy Create free account
hub / github.com/DeusData/codebase-memory-mcp / cbm_client_adapter_pi

Function cbm_client_adapter_pi

src/cli/client_adapter.c:108–186  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

106}
107
108char *cbm_client_adapter_pi(const char *binary_path) {
109 if (!binary_path || !binary_path[0]) {
110 return NULL;
111 }
112 char bin[CBM_SZ_1K];
113 if (!cbm_client_adapter_escape_js(binary_path, bin, sizeof(bin))) {
114 return NULL;
115 }
116 int count = cbm_mcp_tool_count();
117 if (count <= 0) {
118 return NULL;
119 }
120
121 adapter_sb_t sb = {0};
122 emit_header(&sb, "pi");
123 sb_append(&sb, "import { spawn } from 'node:child_process';\n\n");
124 sb_append(&sb, "const BIN = '");
125 sb_append(&sb, bin);
126 sb_append(&sb, "';\n\n");
127
128 /* One shared invoker: the binary prints JSON on stdout, so take the last
129 * line that parses rather than trusting the first — a stray log line on
130 * stdout must not break the bridge. */
131 sb_append(
132 &sb, "async function call(tool, args, signal) {\n"
133 " return new Promise((resolve) => {\n"
134 " const child = spawn(BIN, ['cli', tool, JSON.stringify(args ?? {})], {\n"
135 " stdio: ['ignore', 'pipe', 'pipe'],\n"
136 " env: { ...process.env, CBM_LOG_LEVEL: 'error' },\n"
137 " });\n"
138 " let out = '';\n"
139 " const onAbort = () => { if (!child.killed) child.kill(); };\n"
140 " signal?.addEventListener('abort', onAbort, { once: true });\n"
141 " child.stdout.on('data', (d) => (out += d.toString()));\n"
142 " child.on('error', (e) => {\n"
143 " signal?.removeEventListener('abort', onAbort);\n"
144 " resolve({ error: String(e && e.message ? e.message : e) });\n"
145 " });\n"
146 " child.on('close', () => {\n"
147 " signal?.removeEventListener('abort', onAbort);\n"
148 " const lines = out.split('\\n').map((l) => l.trim()).filter(Boolean);\n"
149 " for (let i = lines.length - 1; i >= 0; i--) {\n"
150 " try { return resolve(JSON.parse(lines[i])); } catch { /* keep scanning */ }\n"
151 " }\n"
152 " resolve({ error: 'no JSON response from codebase-memory-mcp' });\n"
153 " });\n"
154 " });\n"
155 "}\n\n");
156
157 /* Register every tool the registry advertises — never a hand-picked subset,
158 * which is the drift this generator exists to prevent.
159 *
160 * DEFAULT export, and it must stay that way. Pi loads an extension via
161 * jiti.import(path, { default: true }) and rejects anything that is not a
162 * function, so a named `export function register(pi)` hands the loader the
163 * module namespace object instead and every install fails with "Extension
164 * does not export a valid factory function". A Pi extension that fails to
165 * load takes EVERY pi command down with it — `pi doctor` included — not

Callers 1

Calls 5

cbm_mcp_tool_countFunction · 0.85
sb_appendFunction · 0.85
cbm_mcp_tool_nameFunction · 0.85
emit_headerFunction · 0.70

Tested by

no test coverage detected