4040#include "ui/config.h"
4141#include "ui/http_server.h"
4242#include "ui/embedded_assets.h"
43+ #include <yyjson/yyjson.h>
4344
4445#include <stdio.h>
4546#include <stdlib.h>
@@ -61,6 +62,17 @@ static atomic_int g_shutdown = 0;
6162static void signal_handler (int sig ) {
6263 (void )sig ;
6364 atomic_store (& g_shutdown , 1 );
65+
66+ /* Cancel any in-progress pipeline (async-signal-safe: only does atomic_store) */
67+ if (g_server ) {
68+ cbm_pipeline_t * p = cbm_mcp_server_active_pipeline (g_server );
69+ if (p ) {
70+ cbm_pipeline_cancel (p );
71+ }
72+ }
73+ /* Release pipeline lock to prevent stale lock on restart */
74+ cbm_pipeline_unlock ();
75+
6476 if (g_watcher ) {
6577 cbm_watcher_stop (g_watcher );
6678 }
@@ -94,6 +106,11 @@ static void *http_thread(void *arg) {
94106static int watcher_index_fn (const char * project_name , const char * root_path , void * user_data ) {
95107 (void )user_data ;
96108
109+ /* Skip indexing if shutdown is in progress */
110+ if (atomic_load (& g_shutdown )) {
111+ return 0 ;
112+ }
113+
97114 /* Non-blocking: skip if another pipeline is already running.
98115 * Watcher will retry on next poll cycle (5-60s). */
99116 if (!cbm_pipeline_try_lock ()) {
@@ -117,29 +134,65 @@ static int watcher_index_fn(const char *project_name, const char *root_path, voi
117134
118135/* ── CLI mode ───────────────────────────────────────────────────── */
119136
137+ #define CLI_USAGE "Usage: codebase-memory-mcp cli [--progress] [--json] <tool_name> [json_args]\n"
138+
139+ /* Extract text content from MCP tool result envelope and print it.
140+ * MCP results: {"content":[{"type":"text","text":"..."}],"isError":...}
141+ * Returns 1 if the result was an error, 0 otherwise. */
142+ static int cli_print_mcp_result (const char * result ) {
143+ yyjson_doc * doc = yyjson_read (result , strlen (result ), 0 );
144+ if (!doc ) {
145+ printf ("%s\n" , result );
146+ return 0 ;
147+ }
148+
149+ yyjson_val * root = yyjson_doc_get_root (doc );
150+ yyjson_val * err_val = yyjson_obj_get (root , "isError" );
151+ bool is_error = err_val && yyjson_get_bool (err_val );
152+
153+ const char * text = NULL ;
154+ yyjson_val * content = yyjson_obj_get (root , "content" );
155+ if (yyjson_is_arr (content ) && yyjson_arr_size (content ) > 0 ) {
156+ yyjson_val * tv = yyjson_obj_get (yyjson_arr_get_first (content ), "text" );
157+ text = tv ? yyjson_get_str (tv ) : NULL ;
158+ }
159+
160+ if (text ) {
161+ (void )fprintf (is_error ? stderr : stdout , "%s\n" , text );
162+ } else {
163+ printf ("%s\n" , result );
164+ }
165+
166+ yyjson_doc_free (doc );
167+ return is_error ? SKIP_ONE : 0 ;
168+ }
169+
170+ /* Strip a flag from argv, returning true if found. */
171+ static bool cli_strip_flag (int * argc , char * * argv , const char * flag ) {
172+ for (int i = 0 ; i < * argc ; i ++ ) {
173+ if (strcmp (argv [i ], flag ) != 0 ) {
174+ continue ;
175+ }
176+ for (int j = i ; j < * argc - SKIP_ONE ; j ++ ) {
177+ argv [j ] = argv [j + SKIP_ONE ];
178+ }
179+ (* argc )-- ;
180+ return true;
181+ }
182+ return false;
183+ }
184+
120185static int run_cli (int argc , char * * argv ) {
121186 if (argc < MAIN_MIN_ARGC ) {
122- (void )fprintf (stderr ,
123- "Usage: codebase-memory-mcp cli [--progress] <tool_name> [json_args]\n" );
187+ (void )fprintf (stderr , CLI_USAGE );
124188 return SKIP_ONE ;
125189 }
126190
127- /* Strip --progress flag from argv. */
128- bool progress = false;
129- for (int i = 0 ; i < argc ; i ++ ) {
130- if (strcmp (argv [i ], "--progress" ) == 0 ) {
131- progress = true;
132- for (int j = i ; j < argc - SKIP_ONE ; j ++ ) {
133- argv [j ] = argv [j + SKIP_ONE ];
134- }
135- argc -- ;
136- break ;
137- }
138- }
191+ bool progress = cli_strip_flag (& argc , argv , "--progress" );
192+ bool raw_json = cli_strip_flag (& argc , argv , "--json" );
139193
140194 if (argc < MAIN_MIN_ARGC ) {
141- (void )fprintf (stderr ,
142- "Usage: codebase-memory-mcp cli [--progress] <tool_name> [json_args]\n" );
195+ (void )fprintf (stderr , CLI_USAGE );
143196 return SKIP_ONE ;
144197 }
145198
@@ -152,24 +205,30 @@ static int run_cli(int argc, char **argv) {
152205
153206 cbm_mcp_server_t * srv = cbm_mcp_server_new (NULL );
154207 if (!srv ) {
155- (void )fprintf (stderr , "Failed to create server\n" );
208+ (void )fprintf (stderr , "error: failed to create server\n" );
156209 if (progress ) {
157210 cbm_progress_sink_fini ();
158211 }
159212 return SKIP_ONE ;
160213 }
161214
162215 char * result = cbm_mcp_handle_tool (srv , tool_name , args_json );
216+ int exit_code = 0 ;
217+
163218 if (result ) {
164- printf ("%s\n" , result );
219+ if (raw_json ) {
220+ printf ("%s\n" , result );
221+ } else {
222+ exit_code = cli_print_mcp_result (result );
223+ }
165224 free (result );
166225 }
167226
168227 cbm_mcp_server_free (srv );
169228 if (progress ) {
170229 cbm_progress_sink_fini ();
171230 }
172- return 0 ;
231+ return exit_code ;
173232}
174233
175234/* ── Help ───────────────────────────────────────────────────────── */
0 commit comments