4runr-os 1.0.80 → 1.0.82

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,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,CA0DN;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,173 @@
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
+ // Handle Enter key explicitly (blessed textbox needs this)
121
+ inputTextbox.key('enter', () => {
122
+ // Get value from textbox (blessed textbox uses .value property)
123
+ const value = inputTextbox.value || '';
124
+ const trimmed = value.trim();
125
+ if (trimmed) {
126
+ onSubmit(trimmed);
127
+ }
128
+ // Clear input
129
+ inputTextbox.clearValue();
130
+ // Refocus (after submit)
131
+ focusCommandInput(widgets, 'submit');
132
+ });
133
+ // Also handle submit event (in case blessed emits it)
134
+ inputTextbox.on('submit', (value) => {
135
+ const trimmed = value.trim();
136
+ if (trimmed) {
137
+ onSubmit(trimmed);
138
+ }
139
+ // Clear input
140
+ inputTextbox.clearValue();
141
+ // Refocus (after submit)
142
+ focusCommandInput(widgets, 'submit');
143
+ });
144
+ // Optional cancel handler
145
+ if (onCancel) {
146
+ inputTextbox.on('cancel', () => {
147
+ inputTextbox.clearValue();
148
+ onCancel();
149
+ focusCommandInput(widgets, 'cancel');
150
+ });
151
+ }
152
+ // Handle Escape key to clear input
153
+ inputTextbox.key('escape', () => {
154
+ inputTextbox.clearValue();
155
+ focusCommandInput(widgets, 'escape');
156
+ });
157
+ // Do NOT attach screen-level keypress handlers for typing
158
+ // The textbox handles all typing automatically
159
+ // Only use screen keys for global shortcuts (already handled in Section 0)
160
+ }
161
+ /**
162
+ * Update status strip content
163
+ */
164
+ export function updateStatusStrip(widgets, content) {
165
+ widgets.statusStrip.setContent(content);
166
+ }
167
+ /**
168
+ * Reset handler attachment guard (for testing)
169
+ */
170
+ export function resetCommandLineHandlers() {
171
+ commandHandlersAttached = false;
172
+ }
173
+ //# 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.80",
3
+ "version": "1.0.82",
4
4
  "type": "module",
5
5
  "description": "4Runr AI Agent OS - Interactive terminal for managing AI agents",
6
6
  "main": "dist/index.js",