4runr-os 1.0.79 → 1.0.81

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Section 0 - Stable App Shell
4
+ *
5
+ * Objective: Build a minimal TUI app shell that:
6
+ * - starts reliably
7
+ * - exits cleanly
8
+ * - restores the terminal every time
9
+ * - does not register duplicate handlers or multiple render loops
10
+ *
11
+ * No UI panels, no commands, no collectors yet. Just a stable shell.
12
+ */
13
+ /**
14
+ * Start Section 0 TUI shell
15
+ *
16
+ * Rules:
17
+ * - One render loop only (or none for Section 0 - just render once)
18
+ * - No console.log() while TUI is active
19
+ * - Exit must always restore terminal state
20
+ */
21
+ export declare function startSection0(): Promise<void>;
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ui/v3/section0/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;GAUG;AAaH;;;;;;;GAOG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAwDnD"}
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Section 0 - Stable App Shell
4
+ *
5
+ * Objective: Build a minimal TUI app shell that:
6
+ * - starts reliably
7
+ * - exits cleanly
8
+ * - restores the terminal every time
9
+ * - does not register duplicate handlers or multiple render loops
10
+ *
11
+ * No UI panels, no commands, no collectors yet. Just a stable shell.
12
+ */
13
+ import { createScreen } from './runtime/createScreen.js';
14
+ import { initializeLifecycle } from './runtime/lifecycle.js';
15
+ import blessed from 'neo-blessed';
16
+ const blessedLib = blessed;
17
+ // Suppress console.log during TUI (write debug logs to file if needed)
18
+ const originalConsoleLog = console.log;
19
+ const originalConsoleError = console.error;
20
+ /**
21
+ * Start Section 0 TUI shell
22
+ *
23
+ * Rules:
24
+ * - One render loop only (or none for Section 0 - just render once)
25
+ * - No console.log() while TUI is active
26
+ * - Exit must always restore terminal state
27
+ */
28
+ export async function startSection0() {
29
+ // Suppress console.log during TUI
30
+ console.log = () => { };
31
+ // Keep console.error for fatal errors (but restore before using)
32
+ let consoleErrorRestored = false;
33
+ const restoreConsoleError = () => {
34
+ if (!consoleErrorRestored) {
35
+ console.error = originalConsoleError;
36
+ consoleErrorRestored = true;
37
+ }
38
+ };
39
+ try {
40
+ // Create screen (singleton, guarded)
41
+ const screen = createScreen();
42
+ // Initialize lifecycle (exit handlers, guarded against duplicates)
43
+ initializeLifecycle(screen);
44
+ // Create a single centered text node
45
+ const message = '4Runr OS V3 — Shell OK (press q to exit)';
46
+ const textNode = blessedLib.box({
47
+ top: Math.floor((screen.height - 1) / 2),
48
+ left: Math.floor((screen.width - message.length) / 2),
49
+ width: message.length,
50
+ height: 1,
51
+ content: message,
52
+ tags: true,
53
+ style: {
54
+ fg: 'cyan',
55
+ },
56
+ });
57
+ screen.append(textNode);
58
+ // Single render (no loop for Section 0)
59
+ screen.render();
60
+ // Restore console.log after successful start (for future use if needed)
61
+ // But keep it suppressed during TUI operation
62
+ // console.log = originalConsoleLog; // Commented: keep suppressed during TUI
63
+ }
64
+ catch (error) {
65
+ // Restore console.error for error output
66
+ restoreConsoleError();
67
+ console.error('FATAL: Section 0 TUI failed to start:', error);
68
+ // Ensure terminal is restored even on error
69
+ if (process.stdout.isTTY) {
70
+ process.stdout.write('\x1b[?25h'); // Show cursor
71
+ process.stdout.write('\x1b[?1049l'); // Exit alternate screen
72
+ }
73
+ process.exit(1);
74
+ }
75
+ }
76
+ // If run directly (not imported), start the TUI
77
+ // Simple check: if this file is executed directly, start the TUI
78
+ const scriptPath = process.argv[1]?.replace(/\\/g, '/') || '';
79
+ const isMainModule = scriptPath.includes('section0/index.js') ||
80
+ scriptPath.includes('section0/index.ts') ||
81
+ import.meta.url.includes('section0/index');
82
+ if (isMainModule) {
83
+ startSection0().catch((error) => {
84
+ console.error('FATAL: Section 0 failed:', error);
85
+ process.exit(1);
86
+ });
87
+ }
88
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/ui/v3/section0/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,OAAO,MAAM,aAAa,CAAC;AAGlC,MAAM,UAAU,GAAG,OAAc,CAAC;AAElC,uEAAuE;AACvE,MAAM,kBAAkB,GAAG,OAAO,CAAC,GAAG,CAAC;AACvC,MAAM,oBAAoB,GAAG,OAAO,CAAC,KAAK,CAAC;AAE3C;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,kCAAkC;IAClC,OAAO,CAAC,GAAG,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;IAEvB,iEAAiE;IACjE,IAAI,oBAAoB,GAAG,KAAK,CAAC;IACjC,MAAM,mBAAmB,GAAG,GAAG,EAAE;QAC/B,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC1B,OAAO,CAAC,KAAK,GAAG,oBAAoB,CAAC;YACrC,oBAAoB,GAAG,IAAI,CAAC;QAC9B,CAAC;IACH,CAAC,CAAC;IAEF,IAAI,CAAC;QACH,qCAAqC;QACrC,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;QAE9B,mEAAmE;QACnE,mBAAmB,CAAC,MAAM,CAAC,CAAC;QAE5B,qCAAqC;QACrC,MAAM,OAAO,GAAG,0CAA0C,CAAC;QAC3D,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC;YAC9B,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;YACxC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACrD,KAAK,EAAE,OAAO,CAAC,MAAM;YACrB,MAAM,EAAE,CAAC;YACT,OAAO,EAAE,OAAO;YAChB,IAAI,EAAE,IAAI;YACV,KAAK,EAAE;gBACL,EAAE,EAAE,MAAM;aACX;SACF,CAAgB,CAAC;QAElB,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAExB,wCAAwC;QACxC,MAAM,CAAC,MAAM,EAAE,CAAC;QAEhB,wEAAwE;QACxE,8CAA8C;QAC9C,6EAA6E;IAE/E,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,yCAAyC;QACzC,mBAAmB,EAAE,CAAC;QACtB,OAAO,CAAC,KAAK,CAAC,uCAAuC,EAAE,KAAK,CAAC,CAAC;QAE9D,4CAA4C;QAC5C,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YACzB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,cAAc;YACjD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,wBAAwB;QAC/D,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,gDAAgD;AAChD,iEAAiE;AACjE,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;AAC9D,MAAM,YAAY,GAAG,UAAU,CAAC,QAAQ,CAAC,mBAAmB,CAAC;IACxC,UAAU,CAAC,QAAQ,CAAC,mBAAmB,CAAC;IACxC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;AAEhE,IAAI,YAAY,EAAE,CAAC;IACjB,aAAa,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;QAC9B,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Section 0 - Create Screen
3
+ *
4
+ * Responsibilities:
5
+ * - Initialize neo-blessed screen cleanly
6
+ * - Ensure only one screen instance exists
7
+ * - Configure screen with proper settings
8
+ */
9
+ import type { Widgets } from 'neo-blessed';
10
+ /**
11
+ * Create or get the singleton screen instance
12
+ *
13
+ * Rules:
14
+ * - Must only create one screen instance
15
+ * - If screen already exists, return it (do not create another)
16
+ * - Configure with smartCSR, fullUnicode, dockBorders, warnings: false
17
+ */
18
+ export declare function createScreen(): Widgets.Screen;
19
+ /**
20
+ * Get the current screen instance (may be null)
21
+ */
22
+ export declare function getScreen(): Widgets.Screen | null;
23
+ /**
24
+ * Clear the screen instance reference (for testing/cleanup)
25
+ */
26
+ export declare function clearScreen(): void;
27
+ //# sourceMappingURL=createScreen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createScreen.d.ts","sourceRoot":"","sources":["../../../../../src/ui/v3/section0/runtime/createScreen.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAM3C;;;;;;;GAOG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAAC,MAAM,CAyB7C;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAEjD;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAElC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Section 0 - Create Screen
3
+ *
4
+ * Responsibilities:
5
+ * - Initialize neo-blessed screen cleanly
6
+ * - Ensure only one screen instance exists
7
+ * - Configure screen with proper settings
8
+ */
9
+ import blessed from 'neo-blessed';
10
+ const blessedLib = blessed;
11
+ let screenInstance = null;
12
+ /**
13
+ * Create or get the singleton screen instance
14
+ *
15
+ * Rules:
16
+ * - Must only create one screen instance
17
+ * - If screen already exists, return it (do not create another)
18
+ * - Configure with smartCSR, fullUnicode, dockBorders, warnings: false
19
+ */
20
+ export function createScreen() {
21
+ if (screenInstance) {
22
+ return screenInstance;
23
+ }
24
+ screenInstance = blessedLib.screen({
25
+ smartCSR: true,
26
+ fullUnicode: true,
27
+ dockBorders: true,
28
+ warnings: false,
29
+ title: '4Runr OS (Terminal UI V3)',
30
+ });
31
+ if (!screenInstance) {
32
+ throw new Error('Failed to create blessed screen');
33
+ }
34
+ // Hide cursor on start (will be restored on exit)
35
+ if (screenInstance.program && screenInstance.program.hideCursor) {
36
+ screenInstance.program.hideCursor();
37
+ }
38
+ else if (process.stdout.isTTY) {
39
+ process.stdout.write('\x1b[?25l'); // ANSI hide cursor
40
+ }
41
+ return screenInstance;
42
+ }
43
+ /**
44
+ * Get the current screen instance (may be null)
45
+ */
46
+ export function getScreen() {
47
+ return screenInstance;
48
+ }
49
+ /**
50
+ * Clear the screen instance reference (for testing/cleanup)
51
+ */
52
+ export function clearScreen() {
53
+ screenInstance = null;
54
+ }
55
+ //# sourceMappingURL=createScreen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createScreen.js","sourceRoot":"","sources":["../../../../../src/ui/v3/section0/runtime/createScreen.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,OAAO,MAAM,aAAa,CAAC;AAGlC,MAAM,UAAU,GAAG,OAAc,CAAC;AAElC,IAAI,cAAc,GAA0B,IAAI,CAAC;AAEjD;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY;IAC1B,IAAI,cAAc,EAAE,CAAC;QACnB,OAAO,cAAc,CAAC;IACxB,CAAC;IAED,cAAc,GAAG,UAAU,CAAC,MAAM,CAAC;QACjC,QAAQ,EAAE,IAAI;QACd,WAAW,EAAE,IAAI;QACjB,WAAW,EAAE,IAAI;QACjB,QAAQ,EAAE,KAAK;QACf,KAAK,EAAE,2BAA2B;KACnC,CAAmB,CAAC;IAErB,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACrD,CAAC;IAED,kDAAkD;IAClD,IAAK,cAAsB,CAAC,OAAO,IAAK,cAAsB,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;QACjF,cAAsB,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;IAC/C,CAAC;SAAM,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,mBAAmB;IACxD,CAAC;IAED,OAAO,cAAc,CAAC;AACxB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS;IACvB,OAAO,cAAc,CAAC;AACxB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW;IACzB,cAAc,GAAG,IAAI,CAAC;AACxB,CAAC"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Section 0 - Lifecycle Management
3
+ *
4
+ * Responsibilities:
5
+ * - Attach exit handlers (single registration, guarded)
6
+ * - Implement safe shutdown that always restores terminal
7
+ * - Track handler attachment to prevent duplicates
8
+ */
9
+ import type { Widgets } from 'neo-blessed';
10
+ /**
11
+ * Attach exit handlers to screen
12
+ *
13
+ * Rules:
14
+ * - Must attach handlers exactly once (protected by exitHandlersAttached guard)
15
+ * - If called again, must no-op
16
+ * - Registers: q → exit, C-c → exit, escape → exit (optional)
17
+ */
18
+ export declare function attachExitHandlers(screen: Widgets.Screen): void;
19
+ /**
20
+ * Attach process-level exit handlers
21
+ *
22
+ * Rules:
23
+ * - Must attach handlers exactly once (protected by exitHandlersAttached guard)
24
+ * - If called again, must no-op
25
+ * - Registers: SIGINT, SIGTERM
26
+ * - Tracks listeners for cleanup
27
+ */
28
+ export declare function attachProcessExitHandlers(): void;
29
+ /**
30
+ * Initialize all exit handlers (screen + process)
31
+ *
32
+ * This is the main entry point for lifecycle setup.
33
+ */
34
+ export declare function initializeLifecycle(screen: Widgets.Screen): void;
35
+ /**
36
+ * Get internal debug counters (for checkpoint verification)
37
+ *
38
+ * These counters verify:
39
+ * - Exit handlers attach exactly once
40
+ * - Shutdown runs exactly once
41
+ *
42
+ * Example expectation: Pressing q triggers exactly one shutdown path.
43
+ */
44
+ export declare function getDebugCounters(): {
45
+ shutdownCallCount: number;
46
+ screenHandlerAttachmentCount: number;
47
+ processHandlerAttachmentCount: number;
48
+ };
49
+ /**
50
+ * Reset lifecycle state (for testing only)
51
+ */
52
+ export declare function resetLifecycle(): void;
53
+ //# sourceMappingURL=lifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../../../../src/ui/v3/section0/runtime/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAmF3C;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAsB/D;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CAuBhD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAGhE;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,IAAI;IAClC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,4BAA4B,EAAE,MAAM,CAAC;IACrC,6BAA6B,EAAE,MAAM,CAAC;CACvC,CAMA;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAQrC"}
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Section 0 - Lifecycle Management
3
+ *
4
+ * Responsibilities:
5
+ * - Attach exit handlers (single registration, guarded)
6
+ * - Implement safe shutdown that always restores terminal
7
+ * - Track handler attachment to prevent duplicates
8
+ */
9
+ import { getScreen } from './createScreen.js';
10
+ // Guards to prevent duplicate handler attachment
11
+ let screenHandlersAttached = false;
12
+ let processHandlersAttached = false;
13
+ let shuttingDown = false;
14
+ // Internal debug counters (NOT console.log - for checkpoint verification)
15
+ // These track handler attachment and shutdown calls
16
+ let shutdownCallCount = 0;
17
+ let screenHandlerAttachmentCount = 0;
18
+ let processHandlerAttachmentCount = 0;
19
+ // Track attached process listeners for cleanup
20
+ const attachedProcessListeners = [];
21
+ /**
22
+ * Shutdown function that always restores terminal state
23
+ *
24
+ * Rules:
25
+ * - Must run exactly once (protected by shuttingDown guard)
26
+ * - Steps (in order):
27
+ * 1. screen.program.showCursor()
28
+ * 2. screen.destroy() (restores terminal modes)
29
+ * 3. Remove any process listeners we attached
30
+ * 4. process.exit(0)
31
+ */
32
+ function shutdown(reason) {
33
+ // Internal debug counter
34
+ shutdownCallCount++;
35
+ // Guard: ensure shutdown runs exactly once
36
+ if (shuttingDown) {
37
+ return;
38
+ }
39
+ shuttingDown = true;
40
+ const screen = getScreen();
41
+ if (screen) {
42
+ try {
43
+ // Step 1: Show cursor
44
+ if (screen.program && screen.program.showCursor) {
45
+ screen.program.showCursor();
46
+ }
47
+ else if (process.stdout.isTTY) {
48
+ process.stdout.write('\x1b[?25h'); // ANSI show cursor
49
+ }
50
+ // Step 2: Destroy screen (restores terminal modes)
51
+ screen.destroy();
52
+ }
53
+ catch (e) {
54
+ // Ignore destroy errors, but ensure cursor is shown
55
+ if (process.stdout.isTTY) {
56
+ process.stdout.write('\x1b[?25h');
57
+ process.stdout.write('\x1b[?1049l'); // Exit alternate screen if needed
58
+ }
59
+ }
60
+ }
61
+ else {
62
+ // No screen, but ensure cursor is visible
63
+ if (process.stdout.isTTY) {
64
+ process.stdout.write('\x1b[?25h');
65
+ process.stdout.write('\x1b[?1049l');
66
+ }
67
+ }
68
+ // Step 3: Remove process listeners we attached
69
+ for (const { event, listener } of attachedProcessListeners) {
70
+ try {
71
+ process.removeListener(event, listener);
72
+ }
73
+ catch (e) {
74
+ // Ignore removal errors
75
+ }
76
+ }
77
+ attachedProcessListeners.length = 0;
78
+ // Step 4: Exit
79
+ process.exit(0);
80
+ }
81
+ /**
82
+ * Attach exit handlers to screen
83
+ *
84
+ * Rules:
85
+ * - Must attach handlers exactly once (protected by exitHandlersAttached guard)
86
+ * - If called again, must no-op
87
+ * - Registers: q → exit, C-c → exit, escape → exit (optional)
88
+ */
89
+ export function attachExitHandlers(screen) {
90
+ // Guard: ensure handlers are attached exactly once
91
+ if (screenHandlersAttached) {
92
+ return;
93
+ }
94
+ screenHandlersAttached = true;
95
+ screenHandlerAttachmentCount++;
96
+ // q → exit
97
+ screen.key(['q', 'Q'], () => {
98
+ shutdown('q pressed');
99
+ });
100
+ // C-c → exit
101
+ screen.key(['C-c'], () => {
102
+ shutdown('Ctrl+C pressed');
103
+ });
104
+ // escape → exit (optional, as requested)
105
+ screen.key(['escape'], () => {
106
+ shutdown('Escape pressed');
107
+ });
108
+ }
109
+ /**
110
+ * Attach process-level exit handlers
111
+ *
112
+ * Rules:
113
+ * - Must attach handlers exactly once (protected by exitHandlersAttached guard)
114
+ * - If called again, must no-op
115
+ * - Registers: SIGINT, SIGTERM
116
+ * - Tracks listeners for cleanup
117
+ */
118
+ export function attachProcessExitHandlers() {
119
+ // Guard: ensure handlers are attached exactly once
120
+ if (processHandlersAttached) {
121
+ return;
122
+ }
123
+ processHandlersAttached = true;
124
+ processHandlerAttachmentCount++;
125
+ const sigintHandler = () => {
126
+ shutdown('SIGINT received');
127
+ };
128
+ const sigtermHandler = () => {
129
+ shutdown('SIGTERM received');
130
+ };
131
+ process.on('SIGINT', sigintHandler);
132
+ process.on('SIGTERM', sigtermHandler);
133
+ attachedProcessListeners.push({ event: 'SIGINT', listener: sigintHandler }, { event: 'SIGTERM', listener: sigtermHandler });
134
+ }
135
+ /**
136
+ * Initialize all exit handlers (screen + process)
137
+ *
138
+ * This is the main entry point for lifecycle setup.
139
+ */
140
+ export function initializeLifecycle(screen) {
141
+ attachExitHandlers(screen);
142
+ attachProcessExitHandlers();
143
+ }
144
+ /**
145
+ * Get internal debug counters (for checkpoint verification)
146
+ *
147
+ * These counters verify:
148
+ * - Exit handlers attach exactly once
149
+ * - Shutdown runs exactly once
150
+ *
151
+ * Example expectation: Pressing q triggers exactly one shutdown path.
152
+ */
153
+ export function getDebugCounters() {
154
+ return {
155
+ shutdownCallCount,
156
+ screenHandlerAttachmentCount,
157
+ processHandlerAttachmentCount,
158
+ };
159
+ }
160
+ /**
161
+ * Reset lifecycle state (for testing only)
162
+ */
163
+ export function resetLifecycle() {
164
+ screenHandlersAttached = false;
165
+ processHandlersAttached = false;
166
+ shuttingDown = false;
167
+ attachedProcessListeners.length = 0;
168
+ shutdownCallCount = 0;
169
+ screenHandlerAttachmentCount = 0;
170
+ processHandlerAttachmentCount = 0;
171
+ }
172
+ //# sourceMappingURL=lifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../../../../src/ui/v3/section0/runtime/lifecycle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Section 1 - Command Line is the Only Input
4
+ *
5
+ * Clean implementation that fixes:
6
+ * - "typing 4x" → typing appears exactly once
7
+ * - Cursor offset → cursor aligned immediately after prompt
8
+ * - Focus leaks → focus locked to command input
9
+ *
10
+ * Layout: 3 widgets at bottom
11
+ * - Label box: "4runr> " (read-only)
12
+ * - Input textbox: only focusable + only writable
13
+ * - Status strip: read-only status info
14
+ */
15
+ /**
16
+ * Start Section 1 runtime
17
+ */
18
+ export declare function startSection1(): Promise<void>;
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ui/v3/section1/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;GAYG;AAsGH;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAgFnD"}
@@ -0,0 +1,174 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Section 1 - Command Line is the Only Input
4
+ *
5
+ * Clean implementation that fixes:
6
+ * - "typing 4x" → typing appears exactly once
7
+ * - Cursor offset → cursor aligned immediately after prompt
8
+ * - Focus leaks → focus locked to command input
9
+ *
10
+ * Layout: 3 widgets at bottom
11
+ * - Label box: "4runr> " (read-only)
12
+ * - Input textbox: only focusable + only writable
13
+ * - Status strip: read-only status info
14
+ */
15
+ import blessed from 'neo-blessed';
16
+ import { createScreen } from '../section0/runtime/createScreen.js';
17
+ import { initializeLifecycle } from '../section0/runtime/lifecycle.js';
18
+ import { computePhase1Layout } from '../ui/layout/phase1Layout.js';
19
+ import { createCommandLineWidgets, focusCommandInput, attachCommandLineHandlers, updateStatusStrip } from './runtime/commandLine.js';
20
+ import { lockAllPanelsFocus, overrideTabNavigation } from './runtime/focusLock.js';
21
+ const blessedLib = blessed;
22
+ let screen = null;
23
+ let panels = [];
24
+ let commandLineWidgets = null;
25
+ // Command history
26
+ const commandHistory = [];
27
+ let historyIndex = -1;
28
+ /**
29
+ * Create all panels (read-only, non-focusable)
30
+ */
31
+ function createPanels(screen, layout) {
32
+ if (!layout)
33
+ return [];
34
+ const panelNames = ['POSTURE', 'RESOURCES', 'ASSETS', 'OPERATIONS', 'NETWORK', 'CAPABILITIES'];
35
+ const panelRects = [
36
+ layout.posture,
37
+ layout.resources,
38
+ layout.assets,
39
+ layout.operations,
40
+ layout.network,
41
+ layout.capabilities,
42
+ ];
43
+ const createdPanels = [];
44
+ for (let i = 0; i < panelNames.length; i++) {
45
+ const rect = panelRects[i];
46
+ const name = panelNames[i];
47
+ const panel = blessedLib.box({
48
+ top: rect.top,
49
+ left: rect.left,
50
+ width: rect.width,
51
+ height: rect.height,
52
+ border: { type: 'line' },
53
+ tags: true,
54
+ content: `\n ${name} Panel\n\n Content will appear here...`,
55
+ style: {
56
+ border: { fg: 'cyan' },
57
+ fg: 'white',
58
+ },
59
+ // All panels are non-focusable (will be locked by focusLock)
60
+ focusable: false,
61
+ keyable: false,
62
+ mouse: false,
63
+ clickable: false,
64
+ keys: false,
65
+ input: false,
66
+ });
67
+ panel.setLabel(` {cyan-fg}${name}{/}`);
68
+ screen.append(panel);
69
+ createdPanels.push(panel);
70
+ }
71
+ return createdPanels;
72
+ }
73
+ /**
74
+ * Handle command submission
75
+ */
76
+ function handleCommandSubmit(value) {
77
+ // Add to history
78
+ if (value.trim()) {
79
+ commandHistory.push(value);
80
+ if (commandHistory.length > 100) {
81
+ commandHistory.shift(); // Keep last 100
82
+ }
83
+ historyIndex = -1; // Reset history index
84
+ }
85
+ // TODO: Route command (will be implemented in Section 2)
86
+ // For now, just log to operations panel
87
+ const operationsPanel = panels[3]; // OPERATIONS is index 3
88
+ if (operationsPanel) {
89
+ const timestamp = new Date().toISOString();
90
+ const newLine = `[${timestamp}] Command: ${value}`;
91
+ // Get existing content via getContent() or track separately
92
+ const existingContent = operationsPanel.content || '';
93
+ operationsPanel.setContent(existingContent + '\n' + newLine);
94
+ }
95
+ // Update status strip
96
+ if (commandLineWidgets) {
97
+ updateStatusStrip(commandLineWidgets, `MODE: LOCAL | LAST: ${value.substring(0, 20)} | POSTURE: OK`);
98
+ }
99
+ }
100
+ /**
101
+ * Start Section 1 runtime
102
+ */
103
+ export async function startSection1() {
104
+ // Suppress console.log during TUI
105
+ const originalLog = console.log;
106
+ console.log = () => { };
107
+ try {
108
+ // Create screen (from Section 0)
109
+ screen = createScreen();
110
+ if (!screen) {
111
+ throw new Error('Failed to create screen');
112
+ }
113
+ // Initialize lifecycle (exit handlers from Section 0)
114
+ initializeLifecycle(screen);
115
+ // Compute layout
116
+ const layoutResult = computePhase1Layout(screen.width, screen.height);
117
+ if (!layoutResult.ok || !layoutResult.layout) {
118
+ throw new Error(layoutResult.errorMessage || 'Failed to compute layout');
119
+ }
120
+ const layout = layoutResult.layout;
121
+ // Create panels (read-only)
122
+ panels = createPanels(screen, layout);
123
+ // Create command line widgets (3 widgets: label, input, status)
124
+ const commandLineRect = layout.commandLine;
125
+ commandLineWidgets = createCommandLineWidgets(screen, commandLineRect.top, commandLineRect.left, commandLineRect.width, 1 // Height is 1 for single-line input
126
+ );
127
+ // Lock focus on all panels (they redirect clicks to input)
128
+ lockAllPanelsFocus(panels, () => {
129
+ if (commandLineWidgets) {
130
+ focusCommandInput(commandLineWidgets, 'panel-click');
131
+ }
132
+ });
133
+ // Override Tab navigation to refocus input
134
+ overrideTabNavigation(screen, () => {
135
+ if (commandLineWidgets) {
136
+ focusCommandInput(commandLineWidgets, 'tab');
137
+ }
138
+ });
139
+ // Attach command line handlers (deduplicated)
140
+ attachCommandLineHandlers(screen, commandLineWidgets, handleCommandSubmit);
141
+ // Initial focus (once on startup, after render)
142
+ // Use setImmediate to ensure focus happens after initial render
143
+ setImmediate(() => {
144
+ if (commandLineWidgets) {
145
+ focusCommandInput(commandLineWidgets, 'startup');
146
+ }
147
+ });
148
+ // Initial render
149
+ screen.render();
150
+ }
151
+ catch (error) {
152
+ // Restore console.error for error output
153
+ console.error = originalLog;
154
+ console.error('FATAL: Section 1 failed:', error);
155
+ // Ensure terminal is restored
156
+ if (process.stdout.isTTY) {
157
+ process.stdout.write('\x1b[?25h');
158
+ process.stdout.write('\x1b[?1049l');
159
+ }
160
+ process.exit(1);
161
+ }
162
+ }
163
+ // If run directly (not imported), start the TUI
164
+ const scriptPath = process.argv[1]?.replace(/\\/g, '/') || '';
165
+ const isMainModule = scriptPath.includes('section1/index.js') ||
166
+ scriptPath.includes('section1/index.ts') ||
167
+ import.meta.url.includes('section1/index');
168
+ if (isMainModule) {
169
+ startSection1().catch((error) => {
170
+ console.error('FATAL: Section 1 failed:', error);
171
+ process.exit(1);
172
+ });
173
+ }
174
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/ui/v3/section1/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Section 1 - Command Line Input System
3
+ *
4
+ * Clean implementation with:
5
+ * - 3 widgets: Label box, Input textbox, Status strip
6
+ * - Only textbox is focusable
7
+ * - Deduplicated handler registration
8
+ * - Proper cursor alignment
9
+ * - Focus lock
10
+ */
11
+ import type { Widgets } from 'neo-blessed';
12
+ export interface CommandLineWidgets {
13
+ labelBox: Widgets.Box;
14
+ inputTextbox: Widgets.Textbox;
15
+ statusStrip: Widgets.Box;
16
+ }
17
+ /**
18
+ * Create the three command line widgets
19
+ *
20
+ * Layout:
21
+ * [Label Box: "4runr> "] [Input Textbox] [Status Strip]
22
+ */
23
+ export declare function createCommandLineWidgets(screen: Widgets.Screen, top: number, left: number, width: number, height: number): CommandLineWidgets;
24
+ /**
25
+ * Focus command input (without creating refocus loops)
26
+ *
27
+ * Rules:
28
+ * - Call only: once on startup, after submit, after command handling
29
+ * - Do NOT call inside: screen.on("render"), periodic loops, panel renders
30
+ */
31
+ export declare function focusCommandInput(widgets: CommandLineWidgets, reason?: string): void;
32
+ /**
33
+ * Attach command line handlers (deduplicated)
34
+ *
35
+ * Rules:
36
+ * - Attach exactly once (guarded)
37
+ * - Use textbox events only for typing + Enter submission
38
+ * - Use screen keys only for global exit shortcuts (q, Ctrl+C)
39
+ */
40
+ export declare function attachCommandLineHandlers(screen: Widgets.Screen, widgets: CommandLineWidgets, onSubmit: (value: string) => void, onCancel?: () => void): void;
41
+ /**
42
+ * Update status strip content
43
+ */
44
+ export declare function updateStatusStrip(widgets: CommandLineWidgets, content: string): void;
45
+ /**
46
+ * Reset handler attachment guard (for testing)
47
+ */
48
+ export declare function resetCommandLineHandlers(): void;
49
+ //# sourceMappingURL=commandLine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commandLine.d.ts","sourceRoot":"","sources":["../../../../../src/ui/v3/section1/runtime/commandLine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAI3C,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC,OAAO,CAAC;IAC9B,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC;CAC1B;AASD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,OAAO,CAAC,MAAM,EACtB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,kBAAkB,CAmEpB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,kBAAkB,EAC3B,MAAM,CAAC,EAAE,MAAM,GACd,IAAI,CASN;AAED;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,OAAO,CAAC,MAAM,EACtB,OAAO,EAAE,kBAAkB,EAC3B,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,EACjC,QAAQ,CAAC,EAAE,MAAM,IAAI,GACpB,IAAI,CAyCN;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,MAAM,GACd,IAAI,CAEN;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C"}
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Section 1 - Command Line Input System
3
+ *
4
+ * Clean implementation with:
5
+ * - 3 widgets: Label box, Input textbox, Status strip
6
+ * - Only textbox is focusable
7
+ * - Deduplicated handler registration
8
+ * - Proper cursor alignment
9
+ * - Focus lock
10
+ */
11
+ import blessed from 'neo-blessed';
12
+ const blessedLib = blessed;
13
+ const PROMPT = '4runr> ';
14
+ const PROMPT_WIDTH = PROMPT.length;
15
+ const GAP = 1; // Gap between label and input
16
+ // Guard to prevent duplicate handler attachment
17
+ let commandHandlersAttached = false;
18
+ /**
19
+ * Create the three command line widgets
20
+ *
21
+ * Layout:
22
+ * [Label Box: "4runr> "] [Input Textbox] [Status Strip]
23
+ */
24
+ export function createCommandLineWidgets(screen, top, left, width, height) {
25
+ // Calculate widths
26
+ const statusWidth = 40; // Fixed width for status strip
27
+ const inputWidth = width - PROMPT_WIDTH - GAP - statusWidth - GAP;
28
+ // 1. Label box (read-only, non-focusable)
29
+ const labelBox = blessedLib.box({
30
+ top,
31
+ left,
32
+ width: PROMPT_WIDTH,
33
+ height: 1,
34
+ content: PROMPT,
35
+ tags: false, // No tags to avoid width issues
36
+ mouse: false,
37
+ keys: false,
38
+ focusable: false,
39
+ clickable: false,
40
+ });
41
+ // 2. Input textbox (only focusable + only writable)
42
+ const inputTextbox = blessedLib.textbox({
43
+ top,
44
+ left: left + PROMPT_WIDTH + GAP,
45
+ width: inputWidth,
46
+ height: 1,
47
+ inputOnFocus: true,
48
+ keys: true,
49
+ mouse: true,
50
+ censor: false,
51
+ padding: {
52
+ left: 0,
53
+ right: 0,
54
+ top: 0,
55
+ bottom: 0,
56
+ },
57
+ style: {
58
+ fg: 'white',
59
+ focus: {
60
+ fg: 'white',
61
+ },
62
+ },
63
+ });
64
+ // 3. Status strip (read-only, non-focusable)
65
+ const statusStrip = blessedLib.box({
66
+ top,
67
+ left: left + PROMPT_WIDTH + GAP + inputWidth + GAP,
68
+ width: statusWidth,
69
+ height: 1,
70
+ content: 'MODE: LOCAL | CONNECT: ... | POSTURE: ...',
71
+ tags: false,
72
+ mouse: false,
73
+ keys: false,
74
+ focusable: false,
75
+ clickable: false,
76
+ });
77
+ // Append to screen
78
+ screen.append(labelBox);
79
+ screen.append(inputTextbox);
80
+ screen.append(statusStrip);
81
+ return {
82
+ labelBox,
83
+ inputTextbox,
84
+ statusStrip,
85
+ };
86
+ }
87
+ /**
88
+ * Focus command input (without creating refocus loops)
89
+ *
90
+ * Rules:
91
+ * - Call only: once on startup, after submit, after command handling
92
+ * - Do NOT call inside: screen.on("render"), periodic loops, panel renders
93
+ */
94
+ export function focusCommandInput(widgets, reason) {
95
+ // Use setImmediate to ensure focus happens after current render cycle
96
+ setImmediate(() => {
97
+ try {
98
+ widgets.inputTextbox.focus();
99
+ }
100
+ catch (e) {
101
+ // Ignore focus errors (widget might be destroyed)
102
+ }
103
+ });
104
+ }
105
+ /**
106
+ * Attach command line handlers (deduplicated)
107
+ *
108
+ * Rules:
109
+ * - Attach exactly once (guarded)
110
+ * - Use textbox events only for typing + Enter submission
111
+ * - Use screen keys only for global exit shortcuts (q, Ctrl+C)
112
+ */
113
+ export function attachCommandLineHandlers(screen, widgets, onSubmit, onCancel) {
114
+ // Guard: ensure handlers attach exactly once
115
+ if (commandHandlersAttached) {
116
+ return;
117
+ }
118
+ commandHandlersAttached = true;
119
+ const { inputTextbox } = widgets;
120
+ // Single submit handler (textbox.on("submit"))
121
+ inputTextbox.on('submit', (value) => {
122
+ const trimmed = value.trim();
123
+ if (trimmed) {
124
+ onSubmit(trimmed);
125
+ }
126
+ // Clear input
127
+ inputTextbox.clearValue();
128
+ // Refocus (after submit)
129
+ focusCommandInput(widgets, 'submit');
130
+ });
131
+ // Optional cancel handler
132
+ if (onCancel) {
133
+ inputTextbox.on('cancel', () => {
134
+ inputTextbox.clearValue();
135
+ onCancel();
136
+ focusCommandInput(widgets, 'cancel');
137
+ });
138
+ }
139
+ // Handle Escape key to clear input
140
+ inputTextbox.key('escape', () => {
141
+ inputTextbox.clearValue();
142
+ focusCommandInput(widgets, 'escape');
143
+ });
144
+ // Do NOT attach screen-level keypress handlers for typing
145
+ // The textbox handles all typing automatically
146
+ // Only use screen keys for global shortcuts (already handled in Section 0)
147
+ }
148
+ /**
149
+ * Update status strip content
150
+ */
151
+ export function updateStatusStrip(widgets, content) {
152
+ widgets.statusStrip.setContent(content);
153
+ }
154
+ /**
155
+ * Reset handler attachment guard (for testing)
156
+ */
157
+ export function resetCommandLineHandlers() {
158
+ commandHandlersAttached = false;
159
+ }
160
+ //# sourceMappingURL=commandLine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commandLine.js","sourceRoot":"","sources":["../../../../../src/ui/v3/section1/runtime/commandLine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Section 1 - Focus Lock
3
+ *
4
+ * Ensures focus never leaves the command input
5
+ * - Panels are non-focusable
6
+ * - Clicking panels refocuses input
7
+ * - Tab navigation is disabled or overridden
8
+ */
9
+ import type { Widgets } from 'neo-blessed';
10
+ /**
11
+ * Apply focus lock to a panel widget
12
+ *
13
+ * Makes the panel non-focusable and redirects clicks to command input
14
+ */
15
+ export declare function lockPanelFocus(panel: Widgets.Box, refocusInput: () => void): void;
16
+ /**
17
+ * Lock focus on all panels
18
+ */
19
+ export declare function lockAllPanelsFocus(panels: Widgets.Box[], refocusInput: () => void): void;
20
+ /**
21
+ * Override Tab key to refocus input instead of moving focus
22
+ */
23
+ export declare function overrideTabNavigation(screen: Widgets.Screen, refocusInput: () => void): void;
24
+ //# sourceMappingURL=focusLock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"focusLock.d.ts","sourceRoot":"","sources":["../../../../../src/ui/v3/section1/runtime/focusLock.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,OAAO,CAAC,GAAG,EAClB,YAAY,EAAE,MAAM,IAAI,GACvB,IAAI,CAcN;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,OAAO,CAAC,GAAG,EAAE,EACrB,YAAY,EAAE,MAAM,IAAI,GACvB,IAAI,CAIN;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,OAAO,CAAC,MAAM,EACtB,YAAY,EAAE,MAAM,IAAI,GACvB,IAAI,CAIN"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Section 1 - Focus Lock
3
+ *
4
+ * Ensures focus never leaves the command input
5
+ * - Panels are non-focusable
6
+ * - Clicking panels refocuses input
7
+ * - Tab navigation is disabled or overridden
8
+ */
9
+ /**
10
+ * Apply focus lock to a panel widget
11
+ *
12
+ * Makes the panel non-focusable and redirects clicks to command input
13
+ */
14
+ export function lockPanelFocus(panel, refocusInput) {
15
+ // Make panel non-focusable
16
+ panel.focusable = false;
17
+ panel.keyable = false;
18
+ panel.mouse = false;
19
+ panel.clickable = false;
20
+ panel.keys = false;
21
+ panel.input = false;
22
+ panel.inputOnFocus = false;
23
+ // If mouse is needed for future drilldowns, redirect clicks to refocus input
24
+ panel.on('click', () => {
25
+ refocusInput();
26
+ });
27
+ }
28
+ /**
29
+ * Lock focus on all panels
30
+ */
31
+ export function lockAllPanelsFocus(panels, refocusInput) {
32
+ for (const panel of panels) {
33
+ lockPanelFocus(panel, refocusInput);
34
+ }
35
+ }
36
+ /**
37
+ * Override Tab key to refocus input instead of moving focus
38
+ */
39
+ export function overrideTabNavigation(screen, refocusInput) {
40
+ screen.key('tab', () => {
41
+ refocusInput();
42
+ });
43
+ }
44
+ //# sourceMappingURL=focusLock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"focusLock.js","sourceRoot":"","sources":["../../../../../src/ui/v3/section1/runtime/focusLock.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC5B,KAAkB,EAClB,YAAwB;IAExB,2BAA2B;IAC1B,KAAa,CAAC,SAAS,GAAG,KAAK,CAAC;IAChC,KAAa,CAAC,OAAO,GAAG,KAAK,CAAC;IAC9B,KAAa,CAAC,KAAK,GAAG,KAAK,CAAC;IAC5B,KAAa,CAAC,SAAS,GAAG,KAAK,CAAC;IAChC,KAAa,CAAC,IAAI,GAAG,KAAK,CAAC;IAC3B,KAAa,CAAC,KAAK,GAAG,KAAK,CAAC;IAC5B,KAAa,CAAC,YAAY,GAAG,KAAK,CAAC;IAEpC,6EAA6E;IAC7E,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QACrB,YAAY,EAAE,CAAC;IACjB,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAChC,MAAqB,EACrB,YAAwB;IAExB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,cAAc,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;IACtC,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CACnC,MAAsB,EACtB,YAAwB;IAExB,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE;QACrB,YAAY,EAAE,CAAC;IACjB,CAAC,CAAC,CAAC;AACL,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "4runr-os",
3
- "version": "1.0.79",
3
+ "version": "1.0.81",
4
4
  "type": "module",
5
5
  "description": "4Runr AI Agent OS - Interactive terminal for managing AI agents",
6
6
  "main": "dist/index.js",