@@ -64,7 +64,19 @@ pub fn runQueenCommand(allocator: Allocator, args: []const []const u8) !void {
6464 }
6565
6666 if (std .mem .eql (u8 , args [0 ], "supervisor" )) {
67- try runSupervisorMode (allocator );
67+ var sv_config = SupervisorConfig {};
68+ var i : usize = 1 ;
69+ while (i < args .len ) : (i += 1 ) {
70+ if (std .mem .eql (u8 , args [i ], "--daemon" )) {
71+ sv_config .daemon = true ;
72+ } else if (std .mem .eql (u8 , args [i ], "--interval" )) {
73+ i += 1 ;
74+ if (i < args .len ) {
75+ sv_config .interval_sec = std .fmt .parseInt (u64 , args [i ], 10 ) catch 60 ;
76+ }
77+ }
78+ }
79+ try runSupervisorMode (allocator , sv_config );
6880 } else if (std .mem .eql (u8 , args [0 ], "stop" )) {
6981 try stopSupervisor ();
7082 } else if (std .mem .eql (u8 , args [0 ], "start" )) {
@@ -525,9 +537,9 @@ const SupervisorConfig = struct {
525537// ═══════════════════════════════════════════════════════════════════════════════
526538
527539fn writePidFile () ! void {
528- const pid = std .posix .getpid ();
529- const dir = std .fs .cwd ().makeOpenPath (".trinity/queen" , .{}) catch | err | {
530- print (" {s}" ++ qt .E_CROSS ++ " Failed to create .trinity/queen: {s}{s}\n " , .{ RED , @errorName (err ), RESET });
540+ const pid = std .os . linux .getpid ();
541+ var dir = std .fs .cwd ().makeOpenPath (".trinity/queen" , .{}) catch | err | {
542+ print (" {s}" ++ qt .E_CROWN ++ " Failed to create .trinity/queen: {s}{s}\n " , .{ RED , @errorName (err ), RESET });
531543 return err ;
532544 };
533545 defer dir .close ();
@@ -609,7 +621,7 @@ const SupervisorLog = struct {
609621 mutex : std.Thread.Mutex ,
610622
611623 fn init () ! SupervisorLog {
612- const dir = try std .fs .cwd ().makeOpenPath (".trinity/queen" , .{});
624+ var dir = try std .fs .cwd ().makeOpenPath (".trinity/queen" , .{});
613625 defer dir .close ();
614626
615627 const file = try dir .createFile ("supervisor.log" , .{ .truncate = false });
@@ -627,7 +639,7 @@ const SupervisorLog = struct {
627639
628640 const timestamp = std .time .timestamp ();
629641 var buf : [4096 ]u8 = undefined ;
630- const msg = std .fmt .bufPrint (& buf , "[{d}] {s} \n " , .{ timestamp , std . fmt . fmtFmt ( fmt , args ) } ) catch return ;
642+ const msg = std .fmt .bufPrint (& buf , "[{d}] " ++ fmt ++ " \n " , .{timestamp } ++ args ) catch return ;
631643 try self .file .writeAll (msg );
632644 try self .file .sync ();
633645 }
@@ -637,14 +649,36 @@ const SupervisorLog = struct {
637649 }
638650};
639651
640- pub fn runSupervisorMode (allocator : Allocator ) ! void {
652+ pub fn runSupervisorMode (allocator : Allocator , config : SupervisorConfig ) ! void {
641653 const cortex = @import ("queen_cortex.zig" );
642654 const cerebellum = @import ("cerebellum.zig" );
643655 const queen_ofc = @import ("queen_ofc.zig" );
644656 const queen_vmpfc = @import ("queen_vmpfc.zig" );
645657
646- print ("\n {s}" ++ qt .E_CROWN ++ " Queen Supervisor Mode — Autonomous Monitoring{s}\n " , .{ GOLDEN , RESET });
647- print (" Integrating all brain cells for self-healing...\n\n " , .{});
658+ // Check if already running
659+ if (isSupervisorRunning ()) {
660+ print ("{s}" ++ qt .E_SIREN ++ " Supervisor is already running!{s}\n " , .{ RED , RESET });
661+ print (" Use 'tri queen stop' to stop the existing instance.\n " , .{});
662+ return error .AlreadyRunning ;
663+ }
664+
665+ // Write PID file
666+ try writePidFile ();
667+ defer removePidFile ();
668+
669+ // Initialize logging
670+ var log = try SupervisorLog .init ();
671+ defer log .close ();
672+
673+ try log .log ("Supervisor started with interval {d}s" , .{config .interval_sec });
674+
675+ if (! config .daemon ) {
676+ print ("\n {s}" ++ qt .E_CROWN ++ " Queen Supervisor Mode — Autonomous Monitoring{s}\n " , .{ GOLDEN , RESET });
677+ print (" PID: {d}\n " , .{std .os .linux .getpid ()});
678+ print (" Interval: {d}s\n " , .{config .interval_sec });
679+ print (" Log: {s}\n " , .{qt .SUPERVISOR_LOG_PATH });
680+ print (" Integrating all brain cells for self-healing...\n\n " , .{});
681+ }
648682
649683 const tg = qt .initTelegram ();
650684
@@ -661,12 +695,16 @@ pub fn runSupervisorMode(allocator: Allocator) !void {
661695
662696 var cycle : u32 = 0 ;
663697 var last_heal_cycle : u32 = 0 ;
698+ var running = std .atomic .Value (bool ).init (true );
664699
665- while (true ) {
700+ while (running . load ( .acquire ) ) {
666701 cycle += 1 ;
667702 const cycle_start = std .time .timestamp ();
668703
669- print ("{s}=== Supervisor Cycle #{d} ==={s}\n " , .{ GOLDEN , cycle , RESET });
704+ if (! config .daemon ) {
705+ print ("{s}=== Supervisor Cycle #{d} ==={s}\n " , .{ GOLDEN , cycle , RESET });
706+ }
707+ try log .log ("Cycle #{d} started" , .{cycle });
670708
671709 // 1. Collect health from all PFC cells
672710 emitSupervisorStep (1 , 8 , "Collecting PFC cell health" );
@@ -692,7 +730,7 @@ pub fn runSupervisorMode(allocator: Allocator) !void {
692730 emitSupervisorStep (3 , 8 , "System snapshot" );
693731 const snapshot = faculty_board .collectSnapshot (allocator ) catch | err | {
694732 print (" {s}" ++ qt .E_CROSS ++ " Snapshot failed: {s}{s}\n " , .{ RED , @errorName (err ), RESET });
695- sleepInterval ( 300 );
733+ sleepInterruptible ( & running , config . interval_sec );
696734 continue ;
697735 };
698736
@@ -773,20 +811,49 @@ pub fn runSupervisorMode(allocator: Allocator) !void {
773811 }
774812
775813 // 10. Report status summary
776- print (" {s}" ++ qt .E_CHECK ++ " Cycle {d}: {s} | Critical: {d} | Warnings: {d}{s}\n\n " , .{
777- if (health_analysis .critical_count == 0 ) GREEN else RED ,
814+ if (! config .daemon ) {
815+ print (" {s}" ++ qt .E_CHECK ++ " Cycle {d}: {s} | Critical: {d} | Warnings: {d}{s}\n\n " , .{
816+ if (health_analysis .critical_count == 0 ) GREEN else RED ,
817+ cycle ,
818+ if (all_healthy ) "HEALTHY" else "RECOVERING" ,
819+ health_analysis .critical_count ,
820+ health_analysis .warning_count ,
821+ RESET ,
822+ });
823+ }
824+ try log .log ("Cycle #{d}: {s} critical={d} warnings={d}" , .{
778825 cycle ,
779826 if (all_healthy ) "HEALTHY" else "RECOVERING" ,
780827 health_analysis .critical_count ,
781828 health_analysis .warning_count ,
782- RESET ,
783829 });
784830
785831 // 11. Save supervisor state
786832 saveSupervisorState (cycle , pfc_health , health_analysis );
787833
788- // Sleep before next cycle (5 min default for supervisor)
789- sleepInterval (300 );
834+ // 12. Check if we should stop (PID file removed = stop request)
835+ if (! isPidFileValid ()) {
836+ try log .log ("PID file removed, shutting down gracefully" , .{});
837+ running .store (false , .release );
838+ break ;
839+ }
840+
841+ // Sleep before next cycle
842+ try log .log ("Sleeping for {d}s" , .{config .interval_sec });
843+ sleepInterruptible (& running , config .interval_sec );
844+ }
845+
846+ // Shutdown notification
847+ try log .log ("Supervisor stopped after {d} cycles" , .{cycle });
848+ if (tg .enabled ) {
849+ var buf : [128 ]u8 = undefined ;
850+ const msg = std .fmt .bufPrint (& buf , qt .E_CROWN ++ " Supervisor \xd0\xbe\xd1\x81\xd1\x82\xd0\xb0\xd0\xbd\xd0\xbe\xd0\xb2\xd0\xbb\xd0\xb5\xd0\xbd \n\n " ++ // остановлен
851+ "Cycles: {d}" , .{cycle }) catch "" ;
852+ queen_telegram .tgSend (tg , msg );
853+ }
854+
855+ if (! config .daemon ) {
856+ print ("\n {s}" ++ qt .E_CHECK ++ " Supervisor stopped after {d} cycles{s}\n " , .{ GREEN , cycle , RESET });
790857 }
791858}
792859
@@ -1727,11 +1794,10 @@ fn isPidFileValid() bool {
17271794 if (n == 0 ) return false ;
17281795
17291796 const pid_str = buf [0.. n ];
1730- const pid = std .fmt .parseInt (i32 , pid_str , 10 ) catch return false ;
1797+ const file_pid = std .fmt .parseInt (i32 , pid_str , 10 ) catch return false ;
1798+ const my_pid = std .os .linux .getpid ();
17311799
1732- // Check if process exists by sending signal 0
1733- const result = std .posix .kill (pid , 0 );
1734- return result == 0 ;
1800+ return file_pid == my_pid ;
17351801}
17361802
17371803// ═══════════════════════════════════════════════════════════════════════════════
0 commit comments