@@ -220,6 +220,65 @@ pub export fn buildkite_mcp_reset() void {
220220 sessions = .{SessionSlot {}} ** MAX_SESSIONS ;
221221}
222222
223+ // ═══════════════════════════════════════════════════════════════════════
224+ // Standard ABI (ADR-0005 four symbols + ADR-0006 invoke)
225+ // ═══════════════════════════════════════════════════════════════════════
226+
227+ const shim = @import ("cartridge_shim" );
228+
229+ const CARTRIDGE_NAME_PTR : [* :0 ]const u8 = "buildkite-mcp" ;
230+ const CARTRIDGE_VERSION_PTR : [* :0 ]const u8 = "0.1.0" ;
231+
232+ export fn boj_cartridge_init () callconv (.c ) c_int {
233+ return 0 ;
234+ }
235+
236+ export fn boj_cartridge_deinit () callconv (.c ) void {}
237+
238+ export fn boj_cartridge_name () callconv (.c ) [* :0 ]const u8 {
239+ return CARTRIDGE_NAME_PTR ;
240+ }
241+
242+ export fn boj_cartridge_version () callconv (.c ) [* :0 ]const u8 {
243+ return CARTRIDGE_VERSION_PTR ;
244+ }
245+
246+ /// Dispatch the cartridge.json MCP tools. Grade D Alpha stubs.
247+ export fn boj_cartridge_invoke (
248+ tool_name : [* c ]const u8 ,
249+ json_args : [* c ]const u8 ,
250+ out_buf : [* c ]u8 ,
251+ in_out_len : [* c ]usize ,
252+ ) callconv (.c ) i32 {
253+ _ = json_args ;
254+ if (shim .invokeArgsNull (tool_name , out_buf , in_out_len )) return shim .RC_BAD_ARGS ;
255+
256+ const body : []const u8 = if (shim .toolIs (tool_name , "buildkite_list_pipelines" ))
257+ "{\" result\" :{\" items\" :[],\" count\" :0,\" status\" :\" stub\" }}"
258+ else if (shim .toolIs (tool_name , "buildkite_get_pipeline" ))
259+ "{\" result\" :{\" metadata\" :{},\" status\" :\" stub\" }}"
260+ else if (shim .toolIs (tool_name , "buildkite_list_builds" ))
261+ "{\" result\" :{\" items\" :[],\" count\" :0,\" status\" :\" stub\" }}"
262+ else if (shim .toolIs (tool_name , "buildkite_get_build" ))
263+ "{\" result\" :{\" metadata\" :{},\" status\" :\" stub\" }}"
264+ else if (shim .toolIs (tool_name , "buildkite_create_build" ))
265+ "{\" result\" :{\" status\" :\" stub\" }}"
266+ else if (shim .toolIs (tool_name , "buildkite_cancel_build" ))
267+ "{\" result\" :{\" status\" :\" stub\" }}"
268+ else if (shim .toolIs (tool_name , "buildkite_list_jobs" ))
269+ "{\" result\" :{\" items\" :[],\" count\" :0,\" status\" :\" stub\" }}"
270+ else if (shim .toolIs (tool_name , "buildkite_get_job_log" ))
271+ "{\" result\" :{\" metadata\" :{},\" status\" :\" stub\" }}"
272+ else if (shim .toolIs (tool_name , "buildkite_list_artifacts" ))
273+ "{\" result\" :{\" items\" :[],\" count\" :0,\" status\" :\" stub\" }}"
274+ else if (shim .toolIs (tool_name , "buildkite_list_agents" ))
275+ "{\" result\" :{\" items\" :[],\" count\" :0,\" status\" :\" stub\" }}"
276+ else
277+ return shim .RC_UNKNOWN_TOOL ;
278+
279+ return shim .writeResult (out_buf , in_out_len , body );
280+ }
281+
223282test "authenticated session lifecycle" {
224283 buildkite_mcp_reset ();
225284 const slot = buildkite_mcp_authenticate (0 );
@@ -270,3 +329,53 @@ test "slot exhaustion" {
270329 try std .testing .expectEqual (@as (c_int , 0 ), buildkite_mcp_close (slots [0 ]));
271330 try std .testing .expect (buildkite_mcp_authenticate (0 ) >= 0 );
272331}
332+
333+ // ═══════════════════════════════════════════════════════════════════════
334+ // ADR-0006 invoke dispatch tests
335+ // ═══════════════════════════════════════════════════════════════════════
336+
337+ test "boj_cartridge_name returns buildkite-mcp" {
338+ const n = std .mem .span (boj_cartridge_name ());
339+ try std .testing .expectEqualStrings ("buildkite-mcp" , n );
340+ }
341+
342+ test "boj_cartridge_init returns 0" {
343+ try std .testing .expectEqual (@as (c_int , 0 ), boj_cartridge_init ());
344+ }
345+
346+ test "invoke: each declared tool succeeds" {
347+ var buf : [256 ]u8 = undefined ;
348+ const tools = [_ ][]const u8 {
349+ "buildkite_list_pipelines" ,
350+ "buildkite_get_pipeline" ,
351+ "buildkite_list_builds" ,
352+ "buildkite_get_build" ,
353+ "buildkite_create_build" ,
354+ "buildkite_cancel_build" ,
355+ "buildkite_list_jobs" ,
356+ "buildkite_get_job_log" ,
357+ "buildkite_list_artifacts" ,
358+ "buildkite_list_agents" ,
359+ };
360+ for (tools ) | t | {
361+ var len : usize = buf .len ;
362+ const rc = boj_cartridge_invoke (t .ptr , "{}" , & buf , & len );
363+ try std .testing .expectEqual (@as (i32 , 0 ), rc );
364+ try std .testing .expect (std .mem .indexOf (u8 , buf [0.. len ], "result" ) != null );
365+ }
366+ }
367+
368+ test "invoke: unknown tool returns -1" {
369+ var buf : [64 ]u8 = undefined ;
370+ var len : usize = buf .len ;
371+ const rc = boj_cartridge_invoke ("nope" , "{}" , & buf , & len );
372+ try std .testing .expectEqual (@as (i32 , -1 ), rc );
373+ }
374+
375+ test "invoke: buffer too small returns -3" {
376+ var buf : [4 ]u8 = undefined ;
377+ var len : usize = buf .len ;
378+ const rc = boj_cartridge_invoke ("buildkite_list_pipelines" , "{}" , & buf , & len );
379+ try std .testing .expectEqual (@as (i32 , -3 ), rc );
380+ try std .testing .expect (len > 4 );
381+ }
0 commit comments