4runr-os 2.9.125 → 2.9.127

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.
@@ -1291,19 +1291,27 @@ const start = async () => {
1291
1291
  const shutdown = async () => {
1292
1292
  baseLogger.info('Shutting down gateway...');
1293
1293
  try {
1294
- // Shutdown queue system first (let jobs complete)
1294
+ // Close Fastify server first to stop accepting new connections
1295
+ baseLogger.info('Closing Fastify server...');
1296
+ await fastify.close();
1297
+
1298
+ // Shutdown queue system (let jobs complete)
1295
1299
  if (queueInitialized) {
1300
+ baseLogger.info('Shutting down queue...');
1296
1301
  await shutdownQueue();
1297
1302
  }
1298
1303
 
1299
1304
  // Shutdown Sentinel
1300
1305
  if (sentinel) {
1306
+ baseLogger.info('Shutting down Sentinel...');
1301
1307
  sentinel.shutdown();
1302
1308
  }
1303
1309
 
1304
- await fastify.close();
1310
+ // Disconnect databases
1311
+ baseLogger.info('Disconnecting databases...');
1305
1312
  await disconnectPrisma();
1306
1313
  await disconnectRedis();
1314
+
1307
1315
  baseLogger.info('Gateway shut down successfully');
1308
1316
  process.exit(0);
1309
1317
  } catch (err) {
@@ -1312,6 +1320,17 @@ const shutdown = async () => {
1312
1320
  }
1313
1321
  };
1314
1322
 
1323
+ // Handle uncaught errors
1324
+ process.on('uncaughtException', (err) => {
1325
+ baseLogger.error('Uncaught exception:', err);
1326
+ shutdown();
1327
+ });
1328
+
1329
+ process.on('unhandledRejection', (reason, promise) => {
1330
+ baseLogger.error('Unhandled rejection at:', promise, 'reason:', reason);
1331
+ shutdown();
1332
+ });
1333
+
1315
1334
  process.on('SIGTERM', shutdown);
1316
1335
  process.on('SIGINT', shutdown);
1317
1336
 
@@ -11,6 +11,18 @@ use serde::{Deserialize, Serialize};
11
11
  use std::collections::VecDeque;
12
12
  use std::time::{Duration, Instant};
13
13
 
14
+ /// `HH:MM:SS` for Connection Portal activity log (UTC clock; avoids pulling in `chrono`).
15
+ fn wall_clock_hms() -> String {
16
+ let secs = std::time::SystemTime::now()
17
+ .duration_since(std::time::UNIX_EPOCH)
18
+ .map(|d| d.as_secs())
19
+ .unwrap_or(0);
20
+ let h = (secs / 3600) % 24;
21
+ let m = (secs / 60) % 60;
22
+ let s = secs % 60;
23
+ format!("{h:02}:{m:02}:{s:02}")
24
+ }
25
+
14
26
  mod render_scheduler;
15
27
  pub use render_scheduler::{RenderScheduler, RunMode};
16
28
 
@@ -2141,35 +2153,44 @@ impl App {
2141
2153
  self.state.connection_portal.connecting = false;
2142
2154
 
2143
2155
  if let Some(ref det) = self.state.setup_portal.detection_result {
2156
+ let now = wall_clock_hms();
2144
2157
  match self.state.setup_portal.selected_option {
2145
2158
  LocalBundle if !det.local_bundle.available => {
2146
- self.state.connection_portal.error = Some(
2147
- "Setup did not find a vendored local Gateway. Install 4runr-os globally, run from the repo, or set your Gateway URL manually below."
2148
- .into(),
2159
+ self.state.connection_portal.add_log_entry(
2160
+ now,
2161
+ LogLevel::Warning,
2162
+ "Setup did not find a vendored local Gateway. Install 4runr-os globally, run from the repo, or set your Gateway URL manually.".to_string()
2149
2163
  );
2150
2164
  }
2151
2165
  LocalBundle if det.local_bundle.available && !det.local_bundle.running => {
2152
- self.state.connection_portal.error = Some(
2153
- "Local bundle found but nothing responded on :3001 yet. Start the Gateway, then press Enter to connect."
2154
- .into(),
2166
+ self.state.connection_portal.add_log_entry(
2167
+ now,
2168
+ LogLevel::Info,
2169
+ "Local Gateway bundle detected. Start the Gateway (cd apps/gateway && npm start), then press Enter to connect.".to_string()
2155
2170
  );
2156
2171
  }
2157
2172
  CloudServer if !det.cloud_server.available => {
2158
- self.state.connection_portal.error = Some(
2159
- "4Runr Cloud is not available in this build (Coming soon). Use Local Bundle or enter a Custom / self-hosted Gateway URL below."
2160
- .into(),
2173
+ self.state.connection_portal.add_log_entry(
2174
+ now,
2175
+ LogLevel::Warning,
2176
+ "4Runr Cloud is not available in this build (Coming soon). Use Local Bundle or enter a Custom / self-hosted Gateway URL.".to_string()
2161
2177
  );
2162
2178
  }
2163
2179
  CustomUrl if url.is_empty() => {
2164
- self.state.connection_portal.error = Some(
2165
- "Type your Gateway URL below (https://…), then press Enter to connect.".into(),
2180
+ self.state.connection_portal.add_log_entry(
2181
+ now,
2182
+ LogLevel::Info,
2183
+ "Type your Gateway URL (https://…), then press Enter to connect.".to_string()
2166
2184
  );
2167
2185
  }
2168
2186
  _ => {}
2169
2187
  }
2170
2188
  } else if matches!(self.state.setup_portal.selected_option, CustomUrl) && url.is_empty() {
2171
- self.state.connection_portal.error = Some(
2172
- "Type your Gateway URL below, then press Enter to connect.".into(),
2189
+ let now = wall_clock_hms();
2190
+ self.state.connection_portal.add_log_entry(
2191
+ now,
2192
+ LogLevel::Info,
2193
+ "Type your Gateway URL, then press Enter to connect.".to_string()
2173
2194
  );
2174
2195
  }
2175
2196
 
@@ -85,7 +85,7 @@ fn main() -> Result<()> {
85
85
 
86
86
  // Track previous screen to detect portal navigation
87
87
  let mut previous_screen: Option<crate::screens::Screen> = None;
88
- /// Last terminal size while Connection or Setup portal is visible (windowed hosts: sync buffer + clear on dimension drift).
88
+ // Last terminal size while Connection or Setup portal is visible (windowed hosts: sync buffer + clear on dimension drift).
89
89
  let mut standalone_portal_last_terminal_dims: Option<(u16, u16)> = None;
90
90
 
91
91
  // Force initial render
@@ -387,6 +387,9 @@ fn render_content_area(f: &mut Frame, area: Rect, state: &AppState) {
387
387
  render_success(f, area, state);
388
388
  } else if portal.connecting {
389
389
  render_connecting(f, area, state);
390
+ } else if !portal.activity_log.is_empty() {
391
+ // Show activity log with instructions when there's no error
392
+ render_activity_log(f, area, state);
390
393
  } else {
391
394
  // Empty state - show instructions
392
395
  render_instructions(f, area);
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "4runr-os",
3
- "version": "2.9.125",
3
+ "version": "2.9.127",
4
4
  "type": "module",
5
- "description": "4Runr AI Agent OS - Secure terminal interface for AI agents. v2.9.125: Fix global auto-update verification (npm list JSON root vs dependencies). Prior: Gateway /health /ready /metrics DDoS exempt; Connection Portal error UI + 429 hint. ⚠️ Pre-MVP / Development Phase",
5
+ "description": "4Runr AI Agent OS - Secure terminal interface for AI agents. v2.9.127: mk3-tui build fix (no chrono dep activity log timestamps use std). Prior: Portal hints in activity log, Gateway shutdown order, npm auto-update list parsing. ⚠️ Pre-MVP / Development Phase",
6
6
  "main": "dist/index.js",
7
7
  "bin": {
8
8
  "4runr": "dist/index.js",