-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Expand file tree
/
Copy pathcli.h
More file actions
556 lines (444 loc) · 28.8 KB
/
Copy pathcli.h
File metadata and controls
556 lines (444 loc) · 28.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
/*
* cli.h — CLI subcommand handlers for install, uninstall, update, version.
*
* Port of Go cmd/codebase-memory-mcp/ install/update/config logic.
*
* Functions accept explicit paths (home_dir, binary_path) rather than
* reading HOME internally, making them testable with temp directories.
*/
#ifndef CBM_CLI_H
#define CBM_CLI_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
typedef struct cbm_mcp_server cbm_mcp_server_t;
/* ── Version ──────────────────────────────────────────────────── */
/* Set the version string (called from main). */
void cbm_cli_set_version(const char *ver);
/* Get the version string. */
const char *cbm_cli_get_version(void);
/* ── CLI tool arguments (flags / --args-file / --help) ────────── */
/* Convert `--flag value` / `--flag=value` / bare-boolean `--flag` arguments for
* a tool into a JSON arguments object string, using the tool's input_schema to
* type values (string/integer/boolean) and to collect repeated flags into
* array-typed properties. kebab-case flags map to snake_case keys
* (--repo-path -> repo_path). A bare `--` ends flag parsing. On error returns
* NULL and, if err_out is non-NULL, sets *err_out to a heap message the caller
* must free. Caller frees the returned JSON string. */
char *cbm_cli_build_args_json(const char *tool_name, int argc, char **argv, char **err_out);
/* Decide whether `cli <tool>` may take its JSON arguments from stdin, given
* that no --args-file, raw-JSON positional and no --flag form was supplied.
* stdin_is_tty is the caller's isatty(0) result. True only for a non-terminal
* stdin AND a tool whose input_schema declares at least one property; a
* zero-argument tool such as list_projects must never read stdin, because an
* inherited-but-never-closed pipe makes that read block forever (#1359). */
bool cbm_cli_args_from_stdin_allowed(const char *tool_name, bool stdin_is_tty);
/* Print per-tool help (usage + the tool's flags with type/description/required)
* derived from its input_schema, to stdout. Returns 0 if the tool is known,
* non-zero (and prints nothing) if it is not. */
int cbm_cli_print_tool_help(const char *tool_name);
/* Inspect a raw MCP tool-result envelope. Returns true only when the root
* object carries the exact boolean field `isError: true`; malformed JSON,
* strings, and nested lookalikes are not tool errors. */
bool cbm_cli_mcp_result_is_error(const char *result);
/* Maintenance cancellation is authoritative even if a tool races to produce
* a nominal success result. Preserve an existing failure code; otherwise turn
* accepted cancellation into EXIT_FAILURE. */
int cbm_cli_exit_status_after_maintenance(int exit_status, bool maintenance_cancelled);
/* ── Self-update: version comparison ──────────────────────────── */
/* Compare two semver strings (e.g. "0.2.1" vs "0.2.0").
* Returns >0 if a > b, <0 if a < b, 0 if equal.
* Handles v-prefix and -dev suffix. */
int cbm_compare_versions(const char *a, const char *b);
/* ── Shell RC detection ───────────────────────────────────────── */
/* Detect the appropriate shell RC file path for the current user.
* Uses SHELL env var. home_dir is the user's home directory.
* Returns static buffer — do NOT free. Returns "" if unknown. */
const char *cbm_detect_shell_rc(const char *home_dir);
/* ── CLI binary detection ─────────────────────────────────────── */
/* Find a CLI binary by name.
* Checks PATH first, then common install locations.
* Returns static buffer — do NOT free. Returns "" if not found. */
const char *cbm_find_cli(const char *name, const char *home_dir);
/* ── File utilities ───────────────────────────────────────────── */
/* Copy a file from src to dst. Returns 0 on success, -1 on error. */
int cbm_copy_file(const char *src, const char *dst);
/* Copy the running binary into the canonical install target, preserving the
* executable bit, skipping the copy when src and dst are the same file (which
* would otherwise truncate the running binary). Returns 0 on success or skip,
* -1 on error. Regression surface for the install --force binary-swap bug. */
int cbm_copy_binary_to_target(const char *src, const char *dst);
/* Replace a binary file: unlinks the existing file first (handles read-only),
* then creates a new file with the given data and permissions.
* Returns 0 on success, -1 on error. */
int cbm_replace_binary(const char *path, const unsigned char *data, int len, int mode);
/* ── Skill file management ────────────────────────────────────── */
/* Number of skill files. */
#define CBM_SKILL_COUNT 1
/* Skill name/content pair. */
typedef struct {
const char *name; /* e.g. "codebase-memory" */
const char *content; /* full SKILL.md content */
} cbm_skill_t;
/* Get the array of skill definitions. */
const cbm_skill_t *cbm_get_skills(void);
/* Install skills to skills_dir (e.g. ~/.claude/skills/).
* If force is true, overwrite existing skills.
* Returns count of skills written. */
int cbm_install_skills(const char *skills_dir, bool force, bool dry_run);
/* Remove skills from skills_dir.
* Returns count of skills removed. */
int cbm_remove_skills(const char *skills_dir, bool dry_run);
/* Remove old monolithic skill dir if it exists.
* Returns true if it was removed. */
bool cbm_remove_old_monolithic_skill(const char *skills_dir, bool dry_run);
/* ── Editor MCP config management ─────────────────────────────── */
/* Install MCP server entry in Cursor/Windsurf/Gemini JSON config.
* Format: { "mcpServers": { "codebase-memory-mcp": { "command": binary_path } } }
* Preserves existing entries. Returns 0 on success. */
int cbm_install_editor_mcp(const char *binary_path, const char *config_path);
/* Remove MCP server entry from Cursor/Windsurf/Gemini JSON config.
* Returns 0 on success. */
int cbm_remove_editor_mcp(const char *config_path);
int cbm_remove_editor_mcp_owned(const char *binary_path, const char *config_path);
/* Install MCP server entry in OpenClaw JSON config.
* Format: { "mcp": { "servers": { "codebase-memory-mcp":
* { "enabled": true, "command": binary_path, "args": [] } } } }
* Preserves existing entries. Returns 0 on success. */
int cbm_install_openclaw_mcp(const char *binary_path, const char *config_path);
/* Remove MCP server entry from OpenClaw JSON config.
* Returns 0 on success. */
int cbm_remove_openclaw_mcp(const char *config_path);
int cbm_remove_openclaw_mcp_owned(const char *binary_path, const char *config_path);
/* Install MCP server entry in VS Code JSON config.
* Format: { "servers": { "codebase-memory-mcp": { "type": "stdio", "command": binary_path } } }
* Returns 0 on success. */
int cbm_install_vscode_mcp(const char *binary_path, const char *config_path);
/* Remove MCP server entry from VS Code JSON config.
* Returns 0 on success. */
int cbm_remove_vscode_mcp(const char *config_path);
int cbm_remove_vscode_mcp_owned(const char *binary_path, const char *config_path);
/* Install MCP server entry in Zed settings.json.
* Format: { "context_servers": { "codebase-memory-mcp": { "command": path, "args": [] } } }
* Returns 0 on success. */
int cbm_install_zed_mcp(const char *binary_path, const char *config_path);
/* Remove MCP server entry from Zed settings.json.
* Returns 0 on success. */
int cbm_remove_zed_mcp(const char *config_path);
int cbm_remove_zed_mcp_owned(const char *binary_path, const char *config_path);
/* ── Agent detection ──────────────────────────────────────────── */
/* Detected coding agents on the system. */
typedef struct {
bool claude_code; /* ~/.claude/ exists */
bool codex; /* $CODEX_HOME or ~/.codex exists */
bool gemini; /* Gemini settings or executable exists */
bool zed; /* platform-specific Zed config dir exists */
bool opencode; /* opencode on PATH or config exists */
bool antigravity; /* Antigravity CLI config or executable exists */
bool aider; /* aider on PATH */
bool kilocode; /* KiloCode globalStorage dir exists */
bool vscode; /* VS Code User config dir exists */
bool cursor; /* ~/.cursor/ exists */
bool windsurf; /* ~/.codeium/windsurf/ exists */
bool augment; /* ~/.augment/ or Auggie CLI exists */
bool openclaw; /* ~/.openclaw/ exists */
bool kiro; /* ~/.kiro/ exists */
bool junie; /* ~/.junie/ exists */
bool hermes; /* ~/.hermes/ or hermes CLI exists */
bool openhands; /* ~/.openhands/ or openhands CLI exists */
bool cline; /* ~/.cline/ or cline CLI exists */
bool warp; /* Warp footprint or oz/oz-preview/warp-cli exists */
bool qwen; /* ~/.qwen/ or qwen CLI exists */
bool copilot_cli; /* $COPILOT_HOME, ~/.copilot/, or copilot CLI exists */
bool factory_droid; /* ~/.factory/ or droid CLI exists */
bool crush; /* Crush config or CLI exists */
bool goose; /* Goose config or CLI exists */
bool mistral_vibe; /* $VIBE_HOME, ~/.vibe/, or vibe CLI exists */
} cbm_detected_agents_t;
/* Detect which coding agents are installed.
* Checks config dirs and PATH. home_dir is used for config dir checks. */
cbm_detected_agents_t cbm_detect_agents(const char *home_dir);
/* Install or refresh every detected agent integration below home. */
int cbm_install_agent_configs(const char *home, const char *binary_path, bool force, bool dry_run);
#ifdef CBM_CLI_ENABLE_TEST_API
/* #1558: client-selector vocabulary, exposed so a test can prove every token
* resolves and an unknown one is rejected. */
bool cbm_cli_clients_apply_selection_for_testing(const char *spec, cbm_detected_agents_t *detected);
size_t cbm_cli_clients_count_for_testing(void);
const char *cbm_cli_clients_token_for_testing(size_t index);
#endif
#ifdef CBM_CLI_ENABLE_TEST_API
/* #1566: name the package manager that owns a binary path, or NULL when it is
* not recognisably foreign. Detection must be positive evidence — see the
* implementation comment. */
const char *cbm_cli_external_manager_name_for_testing(const char *self_path);
/* #1558: expose the config-key table so a test can prove a key is discoverable
* (`config list`/`set` both walk it). */
size_t cbm_cli_config_key_count_for_testing(void);
const char *cbm_cli_config_key_at_for_testing(size_t index);
#endif
#ifdef CBM_CLI_ENABLE_TEST_API
int cbm_build_qwen_hook_command_for_testing(const char *binary_path, bool windows, char *command,
size_t command_size, char *shell, size_t shell_size);
int cbm_build_qoder_hook_command_for_testing(const char *binary_path, bool windows, char *command,
size_t command_size, char *shell, size_t shell_size);
int cbm_resolve_claude_hook_command_for_testing(const char *script_name, bool windows,
char *command, size_t command_size);
bool cbm_optional_hook_supported_for_testing(const char *agent_name, bool windows);
void cbm_hook_sanitize_metadata_for_testing(const char *input, char *output, size_t output_size);
char *cbm_hook_augment_format_context_for_testing(const char *envelope, const char *token,
bool *is_error);
int cbm_upsert_qwen_lifecycle_hooks_for_testing(const char *settings_path, const char *binary_path,
bool windows);
int cbm_upsert_qoder_context_hooks_for_testing(const char *settings_path, const char *binary_path);
int cbm_remove_qoder_context_hooks_for_testing(const char *settings_path, const char *binary_path);
/* Explicit lifecycle adapter seam for hook protocols whose output envelope is
* not Claude/Gemini-compatible. Returns allocated JSON or NULL to fail open. */
char *cbm_hook_augment_lifecycle_json_for_dialect(const char *input, const char *forced_event,
const char *dialect);
char *cbm_hook_augment_tool_json_for_testing(const char *input, const char *dialect,
const char *context, char *path, size_t path_size);
bool cbm_hook_augment_invocation_supported_for_testing(const char *dialect,
const char *forced_event);
bool cbm_hook_path_contains_for_testing(const char *root, const char *candidate,
bool case_insensitive);
const char *cbm_hook_no_project_index_guidance_for_testing(const char *event);
bool cbm_mcp_command_path_probe_safe_for_testing(const char *command, bool windows);
void cbm_set_mcp_command_path_probe_counter_for_testing(int *counter);
int cbm_install_editor_mcp_with_previous_for_testing(const char *binary_path,
const char *previous_binary_path,
const char *config_path);
int cbm_upsert_junie_mcp_with_previous_for_testing(const char *binary_path,
const char *previous_binary_path,
const char *config_path);
#endif
/* ── Agent MCP config upsert (per agent) ──────────────────────── */
/* Codex CLI: upsert MCP entry in $CODEX_HOME/config.toml. Returns 0 on success. */
int cbm_upsert_codex_mcp(const char *binary_path, const char *config_path);
/* Remove CMM MCP entry from Codex config.toml. Returns 0 on success. */
int cbm_remove_codex_mcp(const char *config_path);
/* OpenCode: upsert MCP entry in opencode.json. Returns 0 on success. */
int cbm_upsert_opencode_mcp(const char *binary_path, const char *config_path);
/* Remove CMM MCP entry from opencode.json. Returns 0 on success. */
int cbm_remove_opencode_mcp(const char *config_path);
int cbm_remove_opencode_mcp_owned(const char *binary_path, const char *config_path);
/* Antigravity: upsert MCP entry in ~/.gemini/config/mcp_config.json.
* Returns 0 on success. */
int cbm_upsert_antigravity_mcp(const char *binary_path, const char *config_path);
/* Remove CMM MCP entry from antigravity mcp_config.json. Returns 0 on success. */
int cbm_remove_antigravity_mcp(const char *config_path);
int cbm_remove_antigravity_mcp_owned(const char *binary_path, const char *config_path);
/* Junie (JetBrains): upsert MCP entry in ~/.junie/mcp/mcp.json (mcpServers format).
* Returns 0 on success. */
int cbm_upsert_junie_mcp(const char *binary_path, const char *config_path);
/* Remove CMM MCP entry from Junie mcp.json. Returns 0 on success. */
int cbm_remove_junie_mcp(const char *config_path);
int cbm_remove_junie_mcp_owned(const char *binary_path, const char *config_path);
/* ── Instructions file upsert ─────────────────────────────────── */
/* Upsert a codebase-memory-mcp instruction section in a markdown file.
* Uses <!-- codebase-memory-mcp:start --> / <!-- codebase-memory-mcp:end --> markers.
* If markers exist, replaces content between them. Otherwise appends.
* If file doesn't exist, creates it. Returns 0 on success. */
int cbm_upsert_instructions(const char *path, const char *content);
/* Remove the codebase-memory-mcp instruction section from a markdown file.
* Returns 0 on success, 1 if not found. */
int cbm_remove_instructions(const char *path);
/* Get the shared agent instructions content (markdown). */
const char *cbm_get_agent_instructions(void);
/* #1032: Aider variant — CLI-form discovery commands (Aider has no MCP). */
const char *cbm_get_aider_instructions(void);
/* ── Pre-tool hook management ─────────────────────────────────── */
/* Upsert a PreToolUse hook in ~/.claude/settings.json for Claude Code.
* Adds a Grep|Glob matcher that reminds to use MCP tools.
* Returns 0 on success. */
int cbm_upsert_claude_hooks(const char *settings_path);
/* Remove our PreToolUse hook from Claude Code settings.json.
* Returns 0 on success. */
int cbm_remove_claude_hooks(const char *settings_path);
/* Write the PreToolUse gate shim to <home>/.claude/hooks/. The shim is a thin
* wrapper that invokes the compiled `hook-augment` and writes to stdout only —
* it must never create a predictable temp/state file (issue #384). Exposed for
* testing that security property. */
bool cbm_install_hook_gate_script(const char *home, const char *binary_path);
/* Upsert a BeforeTool hook in ~/.gemini/settings.json for Gemini CLI.
* Returns 0 on success. */
int cbm_upsert_gemini_hooks(const char *settings_path);
/* Remove our BeforeTool hook from Gemini settings.json.
* Returns 0 on success. */
int cbm_remove_gemini_hooks(const char *settings_path);
/* Install/remove a SessionStart reminder hook in Codex config.toml (#330) and
* Gemini settings.json — same methodology as the Claude Code
* SessionStart hook (non-blocking; stdout injected as session context). */
int cbm_upsert_codex_hooks(const char *config_path);
int cbm_remove_codex_hooks(const char *config_path);
int cbm_upsert_gemini_session_hooks(const char *settings_path);
int cbm_remove_gemini_session_hooks(const char *settings_path);
#ifdef CBM_JSON_LIKE_ENABLE_TEST_API
typedef void (*cbm_hook_json_prewrite_test_hook_t)(const char *settings_path, void *context);
void cbm_set_hook_json_prewrite_hook_for_testing(cbm_hook_json_prewrite_test_hook_t hook,
void *context);
#endif
/* Install/remove a Claude Code SubagentStart reminder hook in settings.json.
* Subagents spawned via the Agent tool do not fire SessionStart, so this is the
* channel that gives them the same code-discovery guidance. Non-blocking; the
* hook injects context via JSON additionalContext. Returns 0 on success. */
int cbm_upsert_claude_subagent_hooks(const char *settings_path);
int cbm_remove_claude_subagent_hooks(const char *settings_path);
/* ── PATH management ──────────────────────────────────────────── */
/* Append an export PATH line to the given rc file.
* Checks if already present. Returns 0 on success, 1 if already present. */
int cbm_ensure_path(const char *bin_dir, const char *rc_file, bool dry_run);
/* ── Codex instructions (legacy, wraps cbm_get_agent_instructions) ── */
/* Get the Codex CLI instructions content. */
const char *cbm_get_codex_instructions(void);
/* ── Tar.gz / zip extraction (TEST-ONLY) ──────────────────────────
* Reachable only from the excluded in-process updater and tests/test_cli.c.
* Declared and defined under the test guard so the capability is absent from
* release artifacts rather than present-but-unreachable. */
#ifdef CBM_CLI_ENABLE_TEST_API
/* Extract a binary named "codebase-memory-mcp*" from a tar.gz buffer.
* Returns malloc'd binary content and sets *out_len.
* Returns NULL on error. Caller must free. */
unsigned char *cbm_extract_binary_from_targz(const unsigned char *data, int data_len, int *out_len);
/* Extract the codebase-memory-mcp binary from a zip archive in memory.
* Returns malloc'd binary content and sets *out_len.
* Returns NULL on error. Caller must free. */
unsigned char *cbm_extract_binary_from_zip(const unsigned char *data, int data_len, int *out_len);
#endif /* CBM_CLI_ENABLE_TEST_API */
/* ── Index management ─────────────────────────────────────────── */
/* List .db files in the cache directory (~/.cache/codebase-memory-mcp/).
* Prints each file path to stdout. Returns count of .db files found. */
int cbm_list_indexes(const char *home_dir);
/* Remove all .db files in the cache directory. Returns count removed. */
int cbm_remove_indexes(const char *home_dir);
/* ── Config store (persistent key-value, backed by _config.db) ── */
typedef struct cbm_config cbm_config_t;
/* Open the config store in the given cache directory.
* Creates _config.db if it doesn't exist. Returns NULL on error. */
cbm_config_t *cbm_config_open(const char *cache_dir);
/* Close the config store. */
void cbm_config_close(cbm_config_t *cfg);
/* Get a config value. Returns default_val if key not found. Database-backed
* results remain valid until the next call on the same thread. */
const char *cbm_config_get(cbm_config_t *cfg, const char *key, const char *default_val);
/* Get a config value as bool. "true"/"1"/"on" → true. */
bool cbm_config_get_bool(cbm_config_t *cfg, const char *key, bool default_val);
/* Get a config value as int. Returns default_val if not found or invalid. */
int cbm_config_get_int(cbm_config_t *cfg, const char *key, int default_val);
/* Set a config value. Returns 0 on success. */
int cbm_config_set(cbm_config_t *cfg, const char *key, const char *value);
/* Delete a config key. Returns 0 on success. */
int cbm_config_delete(cbm_config_t *cfg, const char *key);
/* Well-known config keys */
#define CBM_CONFIG_AUTO_INDEX "auto_index"
#define CBM_CONFIG_AUTO_INDEX_LIMIT "auto_index_limit"
#define CBM_CONFIG_AUTO_WATCH "auto_watch"
#define CBM_CONFIG_UI_LANG "ui-lang"
/* #1558: the graph UI's loopback listener. Stored in the UI config file rather
* than the key-value store, but surfaced through `config` so it is findable. */
#define CBM_CONFIG_UI_ENABLED "ui_enabled"
#define CBM_CONFIG_UI_PORT "ui_port"
/* ── Binary activation safety ─────────────────────────────────── */
typedef void *cbm_cli_activation_lock_t;
typedef int (*cbm_cli_activation_mutation_fn)(void *context);
/* High-level mutation reservation seam. Production maps this to the
* crash-safe version-cohort maintenance barrier, which requests bounded
* quiescence of active modern CBM processes before returning an exclusive
* lease. Tests use it to prove that mutation never runs before the cohort has
* drained. Return 1 with a non-NULL lease on success, 0 when participants did
* not drain before the deadline, or -1 on an unsafe/IO failure. */
typedef int (*cbm_cli_activation_reserve_fn)(void *context, cbm_cli_activation_lock_t *lease_out);
typedef void (*cbm_cli_activation_release_fn)(void *context, cbm_cli_activation_lock_t lease);
/* Injectable high-level boundary for deterministic drain/mutation ordering
* tests. Production never acquires startup while asking participants to
* quiesce: a bootstrap participant may already retain it. Only after lifetime
* EX proves the cohort drained does production acquire startup, re-probe the
* daemon generation, and retain startup through mutation. Startup is released
* before the maintenance lease. */
typedef struct {
void *context;
cbm_cli_activation_reserve_fn reserve_for_mutation;
cbm_cli_activation_release_fn mutation_lease_release;
void (*visible_diagnostic)(void *context, const char *message);
} cbm_cli_activation_ops_t;
/* Reserve and drain the coordinated cohort, run the mutation only while its
* lease is retained, then release it on every callback result. A NULL mutation
* is a guarded no-op. Returns 0 on success, 1 when activation is refused, or
* the mutation callback's non-zero error. */
int cbm_cli_activation_guard_with_ops(const cbm_cli_activation_ops_t *ops,
cbm_cli_activation_mutation_fn mutation,
void *mutation_context);
/* Internal test seam used only by the C suite to route install/update/uninstall
* through deterministic callbacks. NULL restores the production daemon IPC path. */
void cbm_cli_set_activation_ops_for_test(const cbm_cli_activation_ops_t *ops);
/* Internal integration-test seam: isolate the stable endpoint beneath a
* private runtime parent. NULL restores the platform default. This is not a
* command-line or environment override. */
void cbm_cli_set_activation_runtime_parent_for_test(const char *runtime_parent);
/* ── Subcommands (wired from main.c) ─────────────────────────── */
/* install: copy binary, install skills, install editor MCP configs, ensure PATH.
* Prompts to delete old indexes if any exist — rejects on "no". */
int cbm_cmd_install(int argc, char **argv);
/* uninstall: remove skills, remove editor MCP configs, remove binary. */
int cbm_cmd_uninstall(int argc, char **argv);
/* update: check latest release, prompt for index deletion, prompt for ui/standard,
* download and replace binary. */
/* True when the installer script (install.sh / install.ps1 on Windows) is
* present beside the binary. `update` prints a command built from this;
* naming a path that does not exist ends the interaction on a failing
* command (#1632). Exposed for testing. */
bool cbm_cli_installer_beside_binary(const char *dir);
int cbm_cmd_update(int argc, char **argv);
/* config: get/set/list/reset runtime config values. */
int cbm_cmd_config(int argc, char **argv);
/* hook-augment: stdin-driven Claude Code PreToolUse augmenter.
* Reads the hook JSON from stdin and emits hookSpecificOutput.additionalContext
* with search_graph hits for Grep/Glob calls. NEVER blocks: every failure
* path returns 0 with no stdout output. */
int cbm_cmd_hook_augment(int argc, char **argv);
/* Build the documented hookSpecificOutput payload for a SessionStart or
* SubagentStart input. Returns allocated JSON, or NULL for another/invalid
* event. Exposed so lifecycle adapters have contract-level regression tests. */
char *cbm_hook_augment_lifecycle_json(const char *input);
/* Variant used by lifecycle adapters whose stdin omits the event. When
* copilot_dialect is true, emits Copilot CLI's top-level additionalContext. */
char *cbm_hook_augment_lifecycle_json_for(const char *input, const char *forced_event,
bool copilot_dialect);
/* Thin daemon frontend support: preserve the hook's bounded stdin read and
* hard fail-open deadline without constructing a local MCP/store instance. */
void cbm_hook_augment_arm_deadline(void);
char *cbm_hook_augment_read_stdin(void);
/* Why a hook client is not augmenting. The hook caller only ever sees stdout,
* so each reason that is actionable by the user must have a stdout notice
* (#1388: a build-conflicted daemon used to report on stderr alone, which is
* invisible in-session and reads as silent skips). */
typedef enum {
CBM_HOOK_ADMISSION_DAEMON_ABSENT = 0, /* no daemon running: `daemon start` heals it */
CBM_HOOK_ADMISSION_BUILD_CONFLICT /* daemon runs another build: needs `daemon stop` */
} cbm_hook_admission_t;
/* The JSON systemMessage a hook client must print on stdout for `reason`, or
* NULL when nothing should be printed. hook_dialect NULL = Claude Code, the
* only dialect that surfaces a stdout systemMessage to the user. */
const char *cbm_hook_admission_notice(cbm_hook_admission_t reason, const char *hook_dialect);
/* Process one already-read hook payload using a caller-owned MCP session.
* Returns a malloc-owned hook output JSON string, or NULL for fail-open/no
* augmentation. This is the daemon entry; it never arms a process-global
* timer and never constructs a second store/session. */
char *cbm_hook_augment_process(cbm_mcp_server_t *srv, const char *input_json);
/* Dialect-aware daemon entry. forced_event and dialect_name are borrowed and
* may be NULL for the ordinary event dialect. Unsupported combinations fail
* open with NULL, matching the direct hook command. */
bool cbm_hook_augment_invocation_supported(const char *forced_event, const char *dialect_name);
char *cbm_hook_augment_process_for(cbm_mcp_server_t *srv, const char *input_json,
const char *forced_event, const char *dialect_name);
/* True for an absolute path the augmenter can walk up: POSIX "/..." or a
* Windows drive root — "X:/..." or a bare "X:" (callers normalize '\\' to '/'
* first). Exposed for tests — regression coverage for the Windows drive-letter
* no-op (#618). */
bool cbm_hook_path_is_abs(const char *path);
/* Build the agent.install.plan.v1 install receipt for <home> (issue #388):
* a machine-readable JSON list of config/instruction/skill/agent/hook files `install`
* would write, produced WITHOUT mutating anything. Returns a heap JSON string
* (caller frees) or NULL on error. Exposed for `install --plan` and testing. */
char *cbm_build_install_plan_json(const char *home, const char *binary_path);
#endif /* CBM_CLI_H */