@@ -20,16 +20,59 @@ static std::string shellQuote(const std::string& s) {
2020 return r + " '" ;
2121}
2222
23+ static int runEngine (const std::string& input) {
24+ char tmp[] = " /tmp/blackbelt-cpp-XXXXXX" ;
25+ int fd = mkstemp (tmp);
26+ if (fd < 0 ) { perror (" mkstemp" ); return 2 ; }
27+ FILE * fp = fdopen (fd, " wb" );
28+ if (!fp) { perror (" fdopen" ); close (fd); unlink (tmp); return 2 ; }
29+ if (fwrite (input.data (), 1 , input.size (), fp) != input.size () || fputc (' \n ' , fp) == EOF ) {
30+ perror (" write" ); fclose (fp); unlink (tmp); return 2 ;
31+ }
32+ fclose (fp);
33+
34+ const char * env = std::getenv (" BBEA_ENGINE_CMD" );
35+ std::string engine = (env && *env) ? env : " bin/blackbelt-engine.sh" ;
36+ std::string command = " cat " + shellQuote (tmp) + " | " + shellQuote (engine);
37+ int status = std::system (command.c_str ());
38+ unlink (tmp);
39+ if (status == -1 ) return 3 ;
40+ return WIFEXITED (status) ? WEXITSTATUS (status) : 3 ;
41+ }
42+
43+ static int interactive () {
44+ std::cout << " Black Belt Ethical Auditor\n "
45+ << " Enter a JSON audit object, or type 'help' or 'quit'.\n " ;
46+ std::string line;
47+ for (;;) {
48+ std::cout << " black-belt> " << std::flush;
49+ if (!std::getline (std::cin, line)) break ;
50+ if (line.empty ()) continue ;
51+ if (line == " quit" || line == " exit" ) break ;
52+ if (line == " help" ) {
53+ std::cout << " Paste a complete BBEA JSON audit object at the prompt.\n "
54+ << " Commands: help, quit, exit\n " ;
55+ continue ;
56+ }
57+ int rc = runEngine (line);
58+ if (rc != 0 ) std::cerr << " Audit failed (exit " << rc << " ).\n " ;
59+ }
60+ std::cout << ' \n ' ;
61+ return 0 ;
62+ }
63+
2364int main (int argc, char ** argv) {
2465 std::string file;
2566 for (int i = 1 ; i < argc; ++i) {
2667 std::string a = argv[i];
2768 if (a == " --help" || a == " -h" ) { usage (argv[0 ]); return 0 ; }
28- if (a == " --version" ) { std::cout << " blackbelt-cpp 1.0 (BBEA CLI v2 transport)\n " ; return 0 ; }
69+ if (a == " --version" ) { std::cout << " blackbelt-cpp 1.1 (BBEA CLI v2 transport)\n " ; return 0 ; }
2970 if (a == " --file" && i + 1 < argc) { file = argv[++i]; continue ; }
3071 std::cerr << " Unknown argument: " << a << ' \n ' ; usage (argv[0 ]); return 2 ;
3172 }
3273
74+ if (file.empty () && isatty (STDIN_FILENO )) return interactive ();
75+
3376 std::string input;
3477 if (file.empty ()) {
3578 input.assign (std::istreambuf_iterator<char >(std::cin), std::istreambuf_iterator<char >());
@@ -41,20 +84,5 @@ int main(int argc, char** argv) {
4184 if (input.find_first_not_of (" \t\r\n " ) == std::string::npos) {
4285 std::cerr << " No JSON audit input received.\n " ; return 2 ;
4386 }
44-
45- char tmp[] = " /tmp/blackbelt-cpp-XXXXXX" ;
46- int fd = mkstemp (tmp);
47- if (fd < 0 ) { perror (" mkstemp" ); return 2 ; }
48- FILE * fp = fdopen (fd, " wb" );
49- if (!fp) { perror (" fdopen" ); close (fd); unlink (tmp); return 2 ; }
50- fwrite (input.data (), 1 , input.size (), fp);
51- fclose (fp);
52-
53- const char * env = std::getenv (" BBEA_ENGINE_CMD" );
54- std::string engine = (env && *env) ? env : " bin/blackbelt-engine.sh" ;
55- std::string command = " cat " + shellQuote (tmp) + " | " + shellQuote (engine);
56- int status = std::system (command.c_str ());
57- unlink (tmp);
58- if (status == -1 ) return 3 ;
59- return WIFEXITED (status) ? WEXITSTATUS (status) : 3 ;
87+ return runEngine (input);
6088}
0 commit comments