4runr-os 2.10.61 → 2.10.63
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.
- package/apps/gateway/package-lock.json +31 -31
- package/mk3-tui/src/app.rs +35 -9
- package/mk3-tui/src/main.rs +8 -0
- package/mk3-tui/src/ui/sentinel_config.rs +66 -18
- package/package.json +2 -2
|
@@ -241,15 +241,15 @@
|
|
|
241
241
|
}
|
|
242
242
|
},
|
|
243
243
|
"node_modules/@aws-sdk/client-ssm": {
|
|
244
|
-
"version": "3.
|
|
245
|
-
"resolved": "https://registry.npmjs.org/@aws-sdk/client-ssm/-/client-ssm-3.
|
|
246
|
-
"integrity": "sha512-
|
|
244
|
+
"version": "3.1058.0",
|
|
245
|
+
"resolved": "https://registry.npmjs.org/@aws-sdk/client-ssm/-/client-ssm-3.1058.0.tgz",
|
|
246
|
+
"integrity": "sha512-xvJ0IahS3aepnIW1400dApwH3i/eJk+ggXNbNxnjHxjN8gozTFKn80HaboT/husAImv8qzJhZG/9ZeeT7o2USg==",
|
|
247
247
|
"license": "Apache-2.0",
|
|
248
248
|
"dependencies": {
|
|
249
249
|
"@aws-crypto/sha256-browser": "5.2.0",
|
|
250
250
|
"@aws-crypto/sha256-js": "5.2.0",
|
|
251
251
|
"@aws-sdk/core": "^3.974.15",
|
|
252
|
-
"@aws-sdk/credential-provider-node": "^3.972.
|
|
252
|
+
"@aws-sdk/credential-provider-node": "^3.972.48",
|
|
253
253
|
"@aws-sdk/types": "^3.973.9",
|
|
254
254
|
"@smithy/core": "^3.24.5",
|
|
255
255
|
"@smithy/fetch-http-handler": "^5.4.5",
|
|
@@ -2695,13 +2695,13 @@
|
|
|
2695
2695
|
}
|
|
2696
2696
|
},
|
|
2697
2697
|
"node_modules/@smithy/core": {
|
|
2698
|
-
"version": "3.24.
|
|
2699
|
-
"resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.24.
|
|
2700
|
-
"integrity": "sha512-
|
|
2698
|
+
"version": "3.24.6",
|
|
2699
|
+
"resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.24.6.tgz",
|
|
2700
|
+
"integrity": "sha512-wBXDRup6UU97VKyaiRo8AssnfStPtG0oAAfpq/bC0a1YYau8pM86YB4kM6ccoVi1mS8l/UHbn9oDM+7uozr/ug==",
|
|
2701
2701
|
"license": "Apache-2.0",
|
|
2702
2702
|
"dependencies": {
|
|
2703
2703
|
"@aws-crypto/crc32": "5.2.0",
|
|
2704
|
-
"@smithy/types": "^4.14.
|
|
2704
|
+
"@smithy/types": "^4.14.3",
|
|
2705
2705
|
"tslib": "^2.6.2"
|
|
2706
2706
|
},
|
|
2707
2707
|
"engines": {
|
|
@@ -2709,13 +2709,13 @@
|
|
|
2709
2709
|
}
|
|
2710
2710
|
},
|
|
2711
2711
|
"node_modules/@smithy/credential-provider-imds": {
|
|
2712
|
-
"version": "4.3.
|
|
2713
|
-
"resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.3.
|
|
2714
|
-
"integrity": "sha512-
|
|
2712
|
+
"version": "4.3.7",
|
|
2713
|
+
"resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.3.7.tgz",
|
|
2714
|
+
"integrity": "sha512-xj8gq/bjFABAh6qWPSDCYcY3kzQIm4b561C+YnHH4zGq8rOgzQ3Shk+JGlpUxSd41UGiO6FkLdUCtNX1FAeHgg==",
|
|
2715
2715
|
"license": "Apache-2.0",
|
|
2716
2716
|
"dependencies": {
|
|
2717
|
-
"@smithy/core": "^3.24.
|
|
2718
|
-
"@smithy/types": "^4.14.
|
|
2717
|
+
"@smithy/core": "^3.24.6",
|
|
2718
|
+
"@smithy/types": "^4.14.3",
|
|
2719
2719
|
"tslib": "^2.6.2"
|
|
2720
2720
|
},
|
|
2721
2721
|
"engines": {
|
|
@@ -2723,13 +2723,13 @@
|
|
|
2723
2723
|
}
|
|
2724
2724
|
},
|
|
2725
2725
|
"node_modules/@smithy/fetch-http-handler": {
|
|
2726
|
-
"version": "5.4.
|
|
2727
|
-
"resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.4.
|
|
2728
|
-
"integrity": "sha512-
|
|
2726
|
+
"version": "5.4.6",
|
|
2727
|
+
"resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.4.6.tgz",
|
|
2728
|
+
"integrity": "sha512-FEwEYJ1jlBKdhe9TPzfghEi1bP55ZeEImlDkEa62bBBYzUcnB6RUCyuiS2mqKt6ZVjUbBgcNhzfIctH+Hevx9g==",
|
|
2729
2729
|
"license": "Apache-2.0",
|
|
2730
2730
|
"dependencies": {
|
|
2731
|
-
"@smithy/core": "^3.24.
|
|
2732
|
-
"@smithy/types": "^4.14.
|
|
2731
|
+
"@smithy/core": "^3.24.6",
|
|
2732
|
+
"@smithy/types": "^4.14.3",
|
|
2733
2733
|
"tslib": "^2.6.2"
|
|
2734
2734
|
},
|
|
2735
2735
|
"engines": {
|
|
@@ -2749,13 +2749,13 @@
|
|
|
2749
2749
|
}
|
|
2750
2750
|
},
|
|
2751
2751
|
"node_modules/@smithy/node-http-handler": {
|
|
2752
|
-
"version": "4.7.
|
|
2753
|
-
"resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.7.
|
|
2754
|
-
"integrity": "sha512-
|
|
2752
|
+
"version": "4.7.6",
|
|
2753
|
+
"resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.7.6.tgz",
|
|
2754
|
+
"integrity": "sha512-3fya8i7GrJilQouk4cZJKdy5k8MWQBpjfXrRNaXDedH8r779tr0jcxyH3+yoTmsluc2+vF4S343yFbnvu8ExDQ==",
|
|
2755
2755
|
"license": "Apache-2.0",
|
|
2756
2756
|
"dependencies": {
|
|
2757
|
-
"@smithy/core": "^3.24.
|
|
2758
|
-
"@smithy/types": "^4.14.
|
|
2757
|
+
"@smithy/core": "^3.24.6",
|
|
2758
|
+
"@smithy/types": "^4.14.3",
|
|
2759
2759
|
"tslib": "^2.6.2"
|
|
2760
2760
|
},
|
|
2761
2761
|
"engines": {
|
|
@@ -2763,13 +2763,13 @@
|
|
|
2763
2763
|
}
|
|
2764
2764
|
},
|
|
2765
2765
|
"node_modules/@smithy/signature-v4": {
|
|
2766
|
-
"version": "5.4.
|
|
2767
|
-
"resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.4.
|
|
2768
|
-
"integrity": "sha512-
|
|
2766
|
+
"version": "5.4.6",
|
|
2767
|
+
"resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.4.6.tgz",
|
|
2768
|
+
"integrity": "sha512-Ojg4B6oIDlIr1R86xCDJt1zJWnYa0VINmqdjfe9qxWjdRivHalZ3iSlQgVqYbW0MdpFOC5XfHEWsnbmdnpIILQ==",
|
|
2769
2769
|
"license": "Apache-2.0",
|
|
2770
2770
|
"dependencies": {
|
|
2771
|
-
"@smithy/core": "^3.24.
|
|
2772
|
-
"@smithy/types": "^4.14.
|
|
2771
|
+
"@smithy/core": "^3.24.6",
|
|
2772
|
+
"@smithy/types": "^4.14.3",
|
|
2773
2773
|
"tslib": "^2.6.2"
|
|
2774
2774
|
},
|
|
2775
2775
|
"engines": {
|
|
@@ -2777,9 +2777,9 @@
|
|
|
2777
2777
|
}
|
|
2778
2778
|
},
|
|
2779
2779
|
"node_modules/@smithy/types": {
|
|
2780
|
-
"version": "4.14.
|
|
2781
|
-
"resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.14.
|
|
2782
|
-
"integrity": "sha512-
|
|
2780
|
+
"version": "4.14.3",
|
|
2781
|
+
"resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.14.3.tgz",
|
|
2782
|
+
"integrity": "sha512-YupL0ZWmFtJexUN2cHzkvvF/b9pKrtAIfT1o7/oY/Ppu8IYeZ+lDPM5vZdQJaSeA132dJCqojjGC9NhXeF71VQ==",
|
|
2783
2783
|
"license": "Apache-2.0",
|
|
2784
2784
|
"dependencies": {
|
|
2785
2785
|
"tslib": "^2.6.2"
|
package/mk3-tui/src/app.rs
CHANGED
|
@@ -2477,6 +2477,25 @@ impl App {
|
|
|
2477
2477
|
Ok(false)
|
|
2478
2478
|
}
|
|
2479
2479
|
|
|
2480
|
+
pub fn sentinel_scroll_custom_value(&mut self, increase: bool) {
|
|
2481
|
+
self.sentinel_adjust_custom_field(increase);
|
|
2482
|
+
}
|
|
2483
|
+
|
|
2484
|
+
fn sentinel_adjust_custom_field(&mut self, increase: bool) {
|
|
2485
|
+
use crate::ui::sentinel_config::SentinelViewMode;
|
|
2486
|
+
if self.state.sentinel_config.view_mode != SentinelViewMode::Custom {
|
|
2487
|
+
return;
|
|
2488
|
+
}
|
|
2489
|
+
self.state.sentinel_config.adjust_custom_field(increase);
|
|
2490
|
+
// Clear stale apply banner so edits are obvious; shortcuts return in footer
|
|
2491
|
+
self.state.sentinel_config.status_message = None;
|
|
2492
|
+
self.request_immediate_render(if increase {
|
|
2493
|
+
"sentinel_inc"
|
|
2494
|
+
} else {
|
|
2495
|
+
"sentinel_dec"
|
|
2496
|
+
});
|
|
2497
|
+
}
|
|
2498
|
+
|
|
2480
2499
|
/// Handle input when Sentinel Config screen is active
|
|
2481
2500
|
fn handle_sentinel_config_input(
|
|
2482
2501
|
&mut self,
|
|
@@ -2496,34 +2515,41 @@ impl App {
|
|
|
2496
2515
|
match key.code {
|
|
2497
2516
|
KeyCode::Tab => {
|
|
2498
2517
|
self.state.sentinel_config.toggle_view_mode();
|
|
2499
|
-
self.
|
|
2518
|
+
self.request_immediate_render("sentinel_tab");
|
|
2500
2519
|
}
|
|
2501
2520
|
KeyCode::Up => {
|
|
2502
2521
|
self.state.sentinel_config.select_previous();
|
|
2503
|
-
self.
|
|
2522
|
+
self.request_immediate_render("sentinel_up");
|
|
2504
2523
|
}
|
|
2505
2524
|
KeyCode::Down => {
|
|
2506
2525
|
self.state.sentinel_config.select_next();
|
|
2507
|
-
self.
|
|
2526
|
+
self.request_immediate_render("sentinel_down");
|
|
2527
|
+
}
|
|
2528
|
+
KeyCode::Left => {
|
|
2529
|
+
if self.state.sentinel_config.view_mode == SentinelViewMode::Custom {
|
|
2530
|
+
self.sentinel_adjust_custom_field(false);
|
|
2531
|
+
}
|
|
2532
|
+
}
|
|
2533
|
+
KeyCode::Right => {
|
|
2534
|
+
if self.state.sentinel_config.view_mode == SentinelViewMode::Custom {
|
|
2535
|
+
self.sentinel_adjust_custom_field(true);
|
|
2536
|
+
}
|
|
2508
2537
|
}
|
|
2509
2538
|
KeyCode::Char('+') | KeyCode::Char('=') => {
|
|
2510
2539
|
if self.state.sentinel_config.view_mode == SentinelViewMode::Custom {
|
|
2511
|
-
self.
|
|
2512
|
-
self.request_render("sentinel_inc");
|
|
2540
|
+
self.sentinel_adjust_custom_field(true);
|
|
2513
2541
|
}
|
|
2514
2542
|
}
|
|
2515
2543
|
KeyCode::Char('-') | KeyCode::Char('_') => {
|
|
2516
2544
|
if self.state.sentinel_config.view_mode == SentinelViewMode::Custom {
|
|
2517
|
-
self.
|
|
2518
|
-
self.request_render("sentinel_dec");
|
|
2545
|
+
self.sentinel_adjust_custom_field(false);
|
|
2519
2546
|
}
|
|
2520
2547
|
}
|
|
2521
2548
|
KeyCode::Char(' ') => {
|
|
2522
2549
|
if self.state.sentinel_config.view_mode == SentinelViewMode::Custom {
|
|
2523
2550
|
use crate::ui::sentinel_config::CustomField;
|
|
2524
2551
|
if self.state.sentinel_config.custom_field == CustomField::Enabled {
|
|
2525
|
-
self.
|
|
2526
|
-
self.request_render("sentinel_toggle");
|
|
2552
|
+
self.sentinel_adjust_custom_field(true);
|
|
2527
2553
|
}
|
|
2528
2554
|
}
|
|
2529
2555
|
}
|
package/mk3-tui/src/main.rs
CHANGED
|
@@ -1798,6 +1798,14 @@ fn main() -> Result<()> {
|
|
|
1798
1798
|
_ => {}
|
|
1799
1799
|
}
|
|
1800
1800
|
}
|
|
1801
|
+
} else if app.state.navigation.current_screen()
|
|
1802
|
+
== &screens::Screen::SentinelConfig
|
|
1803
|
+
{
|
|
1804
|
+
match mouse.kind {
|
|
1805
|
+
MouseEventKind::ScrollUp => app.sentinel_scroll_custom_value(true),
|
|
1806
|
+
MouseEventKind::ScrollDown => app.sentinel_scroll_custom_value(false),
|
|
1807
|
+
_ => {}
|
|
1808
|
+
}
|
|
1801
1809
|
}
|
|
1802
1810
|
}
|
|
1803
1811
|
Event::Resize(w, h) => {
|
|
@@ -256,11 +256,11 @@ impl SentinelConfigState {
|
|
|
256
256
|
}
|
|
257
257
|
}
|
|
258
258
|
CustomField::MaxCost => {
|
|
259
|
-
let step = 0.
|
|
259
|
+
let step = 0.05;
|
|
260
260
|
if increase {
|
|
261
|
-
d.max_cost = (d.max_cost + step).min(100.0);
|
|
261
|
+
d.max_cost = round_cost((d.max_cost + step).min(100.0));
|
|
262
262
|
} else {
|
|
263
|
-
d.max_cost = (d.max_cost - step).max(0.
|
|
263
|
+
d.max_cost = round_cost((d.max_cost - step).max(0.05));
|
|
264
264
|
}
|
|
265
265
|
}
|
|
266
266
|
CustomField::LoopWindow => {
|
|
@@ -430,10 +430,28 @@ pub fn parse_health(v: &Value) -> SentinelHealthSnapshot {
|
|
|
430
430
|
}
|
|
431
431
|
|
|
432
432
|
fn fmt_ms(ms: u64) -> String {
|
|
433
|
-
|
|
434
|
-
|
|
433
|
+
let total_secs = ms / 1000;
|
|
434
|
+
let mins = total_secs / 60;
|
|
435
|
+
let secs = total_secs % 60;
|
|
436
|
+
if mins > 0 {
|
|
437
|
+
format!("{}:{:02}", mins, secs)
|
|
435
438
|
} else {
|
|
436
|
-
format!("{
|
|
439
|
+
format!("{}s", secs)
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
fn round_cost(usd: f64) -> f64 {
|
|
444
|
+
(usd * 100.0).round() / 100.0
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
fn fmt_cost(usd: f64) -> String {
|
|
448
|
+
let cents = (round_cost(usd) * 100.0).round() as i64;
|
|
449
|
+
let dollars = cents / 100;
|
|
450
|
+
let rem = cents.abs() % 100;
|
|
451
|
+
if rem == 0 {
|
|
452
|
+
format!("${}", dollars)
|
|
453
|
+
} else {
|
|
454
|
+
format!("${}.{:02}", dollars, rem)
|
|
437
455
|
}
|
|
438
456
|
}
|
|
439
457
|
|
|
@@ -449,7 +467,7 @@ fn custom_field_value(d: &SentinelCurrentConfig, field: CustomField) -> String {
|
|
|
449
467
|
CustomField::IdleMs => fmt_ms(d.idle_ms),
|
|
450
468
|
CustomField::MaxDurationMs => fmt_ms(d.duration_ms),
|
|
451
469
|
CustomField::MaxTokens => format!("{}", d.max_tokens),
|
|
452
|
-
CustomField::MaxCost =>
|
|
470
|
+
CustomField::MaxCost => fmt_cost(d.max_cost),
|
|
453
471
|
CustomField::LoopWindow => format!("{}s", d.loop_window),
|
|
454
472
|
CustomField::LoopMax => format!("{}", d.loop_max),
|
|
455
473
|
}
|
|
@@ -511,20 +529,26 @@ pub fn render(f: &mut Frame, state: &AppState) {
|
|
|
511
529
|
"Tab Custom · ↑/↓ Template · Enter Apply · R Refresh · ESC Close"
|
|
512
530
|
}
|
|
513
531
|
SentinelViewMode::Custom => {
|
|
514
|
-
"Tab Templates · ↑/↓ Field · +/-
|
|
532
|
+
"Tab Templates · ↑/↓ Field · ←/→ or +/- Value · Space ON/OFF · Enter Apply · ESC Close"
|
|
515
533
|
}
|
|
516
534
|
};
|
|
535
|
+
const CUSTOM_SHORTCUTS: &str =
|
|
536
|
+
"←/→ or +/- adjust value · wheel · Space ON/OFF · Enter apply · ESC close";
|
|
517
537
|
|
|
518
538
|
let msg = if sc.loading {
|
|
519
|
-
"Loading…"
|
|
539
|
+
"Loading…".to_string()
|
|
520
540
|
} else if sc.applying {
|
|
521
|
-
"Applying…"
|
|
522
|
-
} else if let Some(m) = &sc.status_message {
|
|
523
|
-
m.as_str()
|
|
541
|
+
"Applying…".to_string()
|
|
524
542
|
} else if let Some(e) = &sc.error {
|
|
525
|
-
e.
|
|
543
|
+
e.clone()
|
|
544
|
+
} else if let Some(m) = &sc.status_message {
|
|
545
|
+
if sc.view_mode == SentinelViewMode::Custom {
|
|
546
|
+
format!("{}\n{}", m, CUSTOM_SHORTCUTS)
|
|
547
|
+
} else {
|
|
548
|
+
m.clone()
|
|
549
|
+
}
|
|
526
550
|
} else {
|
|
527
|
-
default_footer
|
|
551
|
+
default_footer.to_string()
|
|
528
552
|
};
|
|
529
553
|
|
|
530
554
|
let footer = Block::default()
|
|
@@ -593,10 +617,7 @@ fn render_active_panel(f: &mut Frame, area: Rect, sc: &SentinelConfigState) {
|
|
|
593
617
|
]),
|
|
594
618
|
Line::from(vec![
|
|
595
619
|
Span::styled("Max cost: ", Style::default().fg(TEXT_DIM)),
|
|
596
|
-
Span::styled(
|
|
597
|
-
format!("${:.2}", sc.current_max_cost),
|
|
598
|
-
Style::default().fg(AMBER_WARN),
|
|
599
|
-
),
|
|
620
|
+
Span::styled(fmt_cost(sc.current_max_cost), Style::default().fg(AMBER_WARN)),
|
|
600
621
|
]),
|
|
601
622
|
Line::from(vec![
|
|
602
623
|
Span::styled("Loop detect: ", Style::default().fg(TEXT_DIM)),
|
|
@@ -731,6 +752,33 @@ fn render_custom_help(f: &mut Frame, area: Rect, sc: &SentinelConfigState) {
|
|
|
731
752
|
Line::from("Set env in docker-compose / shell before connect to keep forever.")
|
|
732
753
|
.style(Style::default().fg(TEXT_MUTED)),
|
|
733
754
|
);
|
|
755
|
+
lines.push(Line::from(""));
|
|
756
|
+
lines.push(
|
|
757
|
+
Line::from("Adjust draft: ←/→ or +/- · mouse wheel · Space toggles Enforcement.")
|
|
758
|
+
.style(Style::default().fg(NEON_GREEN)),
|
|
759
|
+
);
|
|
734
760
|
|
|
735
761
|
f.render_widget(Paragraph::new(lines).wrap(Wrap { trim: false }), inner);
|
|
736
762
|
}
|
|
763
|
+
|
|
764
|
+
#[cfg(test)]
|
|
765
|
+
mod format_tests {
|
|
766
|
+
use super::{fmt_cost, fmt_ms};
|
|
767
|
+
|
|
768
|
+
#[test]
|
|
769
|
+
fn fmt_ms_shows_minutes_and_seconds() {
|
|
770
|
+
assert_eq!(fmt_ms(30_000), "30s");
|
|
771
|
+
assert_eq!(fmt_ms(60_000), "1:00");
|
|
772
|
+
assert_eq!(fmt_ms(75_000), "1:15");
|
|
773
|
+
assert_eq!(fmt_ms(240_000), "4:00");
|
|
774
|
+
assert_eq!(fmt_ms(255_000), "4:15");
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
#[test]
|
|
778
|
+
fn fmt_cost_shows_cents_when_present() {
|
|
779
|
+
assert_eq!(fmt_cost(1.0), "$1");
|
|
780
|
+
assert_eq!(fmt_cost(1.05), "$1.05");
|
|
781
|
+
assert_eq!(fmt_cost(1.15), "$1.15");
|
|
782
|
+
assert_eq!(fmt_cost(1.25), "$1.25");
|
|
783
|
+
}
|
|
784
|
+
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "4runr-os",
|
|
3
|
-
"version": "2.10.
|
|
3
|
+
"version": "2.10.63",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "4Runr AI Agent OS - Secure terminal interface for AI agents. v2.10.
|
|
5
|
+
"description": "4Runr AI Agent OS - Secure terminal interface for AI agents. v2.10.63: Sentinel Custom — M:SS time display, cent-level cost steps.",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"bin": {
|
|
8
8
|
"4runr": "dist/index.js",
|