@agentikos/omega-os 0.19.38 → 0.19.40
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/bootstrap/lib/common.sh +19 -10
- package/bootstrap/templates/aisb/architect.md +27 -1
- package/bootstrap/templates/aisb/construct.md +27 -1
- package/bootstrap/templates/aisb/keymaker.md +27 -1
- package/bootstrap/templates/aisb/link.md +27 -1
- package/bootstrap/templates/aisb/lmc-protocol.md +27 -1
- package/bootstrap/templates/aisb/merovingian.md +27 -1
- package/bootstrap/templates/aisb/morpheus.md +27 -1
- package/bootstrap/templates/aisb/neo.md +27 -1
- package/bootstrap/templates/aisb/niobe.md +27 -1
- package/bootstrap/templates/aisb/oracle.md +27 -1
- package/bootstrap/templates/aisb/pythia.md +36 -0
- package/bootstrap/templates/aisb/seraph.md +27 -1
- package/bootstrap/templates/aisb/smith.md +27 -1
- package/bootstrap/templates/aisb/zion.md +27 -1
- package/omega/Agentik_Engine/omega_engine/__init__.py +1 -1
- package/omega/Agentik_Engine/omega_engine/__pycache__/__init__.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/cli.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/paperclip_bridge.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/prompt_audit.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/tmux.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/tui.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/cli.py +39 -0
- package/omega/Agentik_Engine/omega_engine/paperclip_bridge.py +110 -0
- package/omega/Agentik_Engine/omega_engine/prompt_audit.py +395 -0
- package/omega/Agentik_Engine/omega_engine/tmux.py +61 -26
- package/omega/Agentik_Engine/omega_engine/tui.py +293 -86
- package/omega/Agentik_Engine/pyproject.toml +1 -1
- package/omega/Agentik_Engine/tests/__pycache__/test_install_ux.cpython-313-pytest-8.4.2.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_install_ux.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_paperclip_status.cpython-313-pytest-8.4.2.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_paperclip_status.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_prompt_audit.cpython-313-pytest-8.4.2.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_prompt_audit.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_tmux_palette.cpython-313-pytest-8.4.2.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_tmux_palette.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_tui_runtime.cpython-313-pytest-8.4.2.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_tui_runtime.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/tests/test_install_ux.py +87 -2
- package/omega/Agentik_Engine/tests/test_paperclip_status.py +142 -0
- package/omega/Agentik_Engine/tests/test_prompt_audit.py +281 -0
- package/omega/Agentik_Engine/tests/test_tmux_palette.py +94 -0
- package/omega/Agentik_Engine/tests/test_tui_runtime.py +156 -0
- package/omega/Agentik_SSOT/VERSION +1 -1
- package/omega/Agentik_SSOT/docs/AUDIT-V0.19.39.md +161 -0
- package/omega/Agentik_SSOT/docs/AUDIT-V0.19.40.md +163 -0
- package/omega/Agentik_SSOT/rules/audit-gates.md +189 -0
- package/omega/Agentik_SSOT/rules/constitution.md +7 -0
- package/omega/Agentik_SSOT/rules/orchestration.md +215 -0
- package/omega/Agentik_SSOT/rules/prompt-protocols.md +219 -0
- package/omega/Agentik_SSOT/rules/scope-safety.md +197 -0
- package/omega/Agentik_SSOT/rules/three-laws.md +214 -0
- package/omega/Agentik_SSOT/rules/verified-completion.md +216 -0
- package/package.json +1 -1
|
@@ -325,6 +325,22 @@ def _spawn_with_shell_then_run(
|
|
|
325
325
|
return name
|
|
326
326
|
|
|
327
327
|
|
|
328
|
+
def omega_window_alive(window_name: str) -> bool:
|
|
329
|
+
"""True if a window named ``window_name`` exists inside the Omega
|
|
330
|
+
master tmux session.
|
|
331
|
+
|
|
332
|
+
Used by the TUI chat-list panel to render ● (alive) vs ○ (off) next
|
|
333
|
+
to AISB-chat / Hermès-chat. Cheap — one ``tmux list-windows`` call;
|
|
334
|
+
returns False on any error including 'no Omega session'.
|
|
335
|
+
"""
|
|
336
|
+
if not is_alive("Omega"):
|
|
337
|
+
return False
|
|
338
|
+
rc, out = _tmux("list-windows", "-t", "Omega", "-F", "#W")
|
|
339
|
+
if rc != 0:
|
|
340
|
+
return False
|
|
341
|
+
return window_name in (out or "").splitlines()
|
|
342
|
+
|
|
343
|
+
|
|
328
344
|
def spawn_chat_in_omega(
|
|
329
345
|
window_name: str,
|
|
330
346
|
*,
|
|
@@ -567,7 +583,7 @@ set -s escape-time 10
|
|
|
567
583
|
# session (AISB / oracle / worker / dev / linear / home / other) without
|
|
568
584
|
# leaving tmux.
|
|
569
585
|
# ════════════════════════════════════════════════════════════════════
|
|
570
|
-
bind-key Z display-popup -E -w
|
|
586
|
+
bind-key Z display-popup -E -w 100% -h 100% "omega tmux menu"
|
|
571
587
|
|
|
572
588
|
# Prefix+S — native session list (tmux's built-in choose-tree)
|
|
573
589
|
bind-key S choose-tree -Zs
|
|
@@ -575,18 +591,28 @@ bind-key S choose-tree -Zs
|
|
|
575
591
|
# Option+/ → session switcher (fzf popup, pick any live tmux session)
|
|
576
592
|
# Option+z → Omega action menu (spawn Omega if missing + switch-client)
|
|
577
593
|
# macOS Option key → enable "Use Option as Meta" in your terminal.
|
|
578
|
-
bind-key -n M-/ display-popup -E -
|
|
594
|
+
bind-key -n M-/ display-popup -E -w 100% -h 100% "omega tmux switcher"
|
|
579
595
|
bind-key -n M-z run-shell -b "tmux has-session -t Omega 2>/dev/null || tmux new-session -d -s Omega -n menu -c $HOME 'omega menu-tui'; tmux switch-client -t Omega"
|
|
580
596
|
|
|
581
597
|
# ════════════════════════════════════════════════════════════════════
|
|
582
|
-
#
|
|
598
|
+
# Pixel/CRT amber theme (tmux-claude inspired)
|
|
599
|
+
# xterm colour137 ≈ #af8700 — amber/gold on whatever your terminal bg is.
|
|
600
|
+
# Theme-neutral: inherits terminal background, works in light + dark.
|
|
583
601
|
# ════════════════════════════════════════════════════════════════════
|
|
584
|
-
set -g status-style "
|
|
585
|
-
set -g status-left
|
|
586
|
-
set -g status-right
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
602
|
+
set -g status-style "fg=default"
|
|
603
|
+
set -g status-left ' #[fg=colour137,bold]Ω #S #[fg=default,nobold]• #[fg=colour137]#(omega tmux count 2>/dev/null) sess #[fg=default]• #[fg=colour137]%H:%M '
|
|
604
|
+
set -g status-right '#[fg=default]TS #[fg=colour137]#(omega tmux count 2>/dev/null) #[fg=default]• #[fg=colour137]Ω '
|
|
605
|
+
|
|
606
|
+
# Hide the window list (tmux-claude clean look).
|
|
607
|
+
setw -g window-status-format ''
|
|
608
|
+
setw -g window-status-current-format ''
|
|
609
|
+
setw -g window-status-separator ''
|
|
610
|
+
|
|
611
|
+
# Pane borders — amber on active, inherit on inactive.
|
|
612
|
+
set -g pane-border-style "fg=default"
|
|
613
|
+
set -g pane-active-border-style "fg=colour137"
|
|
614
|
+
set -g message-style "fg=colour137,bg=default,bold"
|
|
615
|
+
set -g mode-style "fg=default,bg=colour137"
|
|
590
616
|
"""
|
|
591
617
|
|
|
592
618
|
|
|
@@ -665,7 +691,7 @@ set -g @scroll-without-changing-pane on
|
|
|
665
691
|
# Prefix+Z — OmegaOS session picker
|
|
666
692
|
# Opens a tmux popup with `omega tmux menu`.
|
|
667
693
|
# ════════════════════════════════════════════════════════════════════
|
|
668
|
-
bind-key Z display-popup -E -w
|
|
694
|
+
bind-key Z display-popup -E -w 100% -h 100% "omega tmux menu"
|
|
669
695
|
|
|
670
696
|
# Prefix+S — native choose-tree
|
|
671
697
|
bind-key S choose-tree -Zs
|
|
@@ -693,30 +719,39 @@ bind-key r source-file ~/.tmux.conf \\; display-message "tmux.conf reloaded"
|
|
|
693
719
|
# ────────────────────────────────────────────────────────────────────
|
|
694
720
|
# popup -E runs the command in a tmux popup overlay (modal). The popup
|
|
695
721
|
# closes when the command exits, returning the user to their previous
|
|
696
|
-
# pane. -
|
|
697
|
-
bind-key -n M-/ display-popup -E -
|
|
722
|
+
# pane. -w 100% -h 100% gives a full-screen popup (tmux-claude style).
|
|
723
|
+
bind-key -n M-/ display-popup -E -w 100% -h 100% "omega tmux switcher"
|
|
698
724
|
bind-key -n M-z run-shell -b "tmux has-session -t Omega 2>/dev/null || tmux new-session -d -s Omega -n menu -c $HOME 'omega menu-tui'; tmux switch-client -t Omega"
|
|
699
725
|
|
|
700
726
|
# ════════════════════════════════════════════════════════════════════
|
|
701
|
-
#
|
|
727
|
+
# Pixel/CRT amber theme (tmux-claude inspired)
|
|
702
728
|
# ════════════════════════════════════════════════════════════════════
|
|
703
|
-
#
|
|
704
|
-
#
|
|
705
|
-
#
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
729
|
+
# xterm colour137 ≈ #af8700 — amber/gold. Theme-neutral: status bar
|
|
730
|
+
# inherits the terminal background, so it looks right in any color
|
|
731
|
+
# scheme (dark, light, solarized, etc.).
|
|
732
|
+
#
|
|
733
|
+
# Bullets `•` everywhere as separators, accent colour137 for values,
|
|
734
|
+
# default fg for labels. Window list HIDDEN (tmux-claude clean look) —
|
|
735
|
+
# the operator switches via Option+/ or `omega tmux menu` instead.
|
|
736
|
+
set -g status-style "fg=default"
|
|
737
|
+
set -g status-left ' #[fg=colour137,bold]Ω #S #[fg=default,nobold]• #[fg=colour137]#(omega tmux count 2>/dev/null) sess #[fg=default]• #[fg=colour137]%H:%M '
|
|
738
|
+
set -g status-right '#[fg=default]CPU #[fg=colour137]#(awk "{print int(\\$1*100/$(nproc))}" /proc/loadavg 2>/dev/null || echo --)% #[fg=default]• #[fg=colour137]Ω v#(cat $OMEGA_HOME/Agentik_SSOT/VERSION 2>/dev/null || echo dev) '
|
|
709
739
|
set -g status-interval 5
|
|
710
|
-
set -g status-left-length
|
|
740
|
+
set -g status-left-length 60
|
|
711
741
|
set -g status-right-length 60
|
|
712
742
|
|
|
713
|
-
#
|
|
714
|
-
|
|
715
|
-
|
|
743
|
+
# Hide the window list (tmux-claude clean look).
|
|
744
|
+
setw -g window-status-format ''
|
|
745
|
+
setw -g window-status-current-format ''
|
|
746
|
+
setw -g window-status-separator ''
|
|
747
|
+
|
|
748
|
+
# Pane borders — amber on active, inherit on inactive.
|
|
749
|
+
set -g pane-border-style "fg=default"
|
|
750
|
+
set -g pane-active-border-style "fg=colour137"
|
|
716
751
|
|
|
717
|
-
# Message + copy-mode prompts —
|
|
718
|
-
set -g message-style "bg
|
|
719
|
-
set -g mode-style "bg
|
|
752
|
+
# Message + copy-mode prompts — amber on terminal bg.
|
|
753
|
+
set -g message-style "fg=colour137,bg=default,bold"
|
|
754
|
+
set -g mode-style "fg=default,bg=colour137"
|
|
720
755
|
"""
|
|
721
756
|
|
|
722
757
|
|
|
@@ -441,11 +441,16 @@ def _arrow_menu() -> int:
|
|
|
441
441
|
OMEGA_BIN = str(HOME / "Agentik_Tools" / "bin" / "omega")
|
|
442
442
|
|
|
443
443
|
# ANSI escapes — used via fzf --ansi.
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
444
|
+
# Pixel/CRT amber palette — colour137 family.
|
|
445
|
+
# Inherits terminal background (no cream); accent = amber gold.
|
|
446
|
+
AMBER = "\033[38;5;137m" # xterm 256 colour137 = amber gold
|
|
447
|
+
AMBER_BR = "\033[38;5;215m" # brighter amber for active/highlighted rows
|
|
448
|
+
MUTED = "\033[38;5;240m" # dim gray
|
|
449
|
+
BOLD = "\033[1m"
|
|
450
|
+
DIM = "\033[2m"
|
|
451
|
+
RST = "\033[0m"
|
|
452
|
+
# Backward-compat alias — existing code may reference ORANGE.
|
|
453
|
+
ORANGE = AMBER
|
|
449
454
|
|
|
450
455
|
def _label(name: str, hint: str = "") -> str:
|
|
451
456
|
"""Two-column label: name on the left, hint dimmed on the right."""
|
|
@@ -462,46 +467,180 @@ def _arrow_menu() -> int:
|
|
|
462
467
|
# `omega_engine.provider_state` module both can read.
|
|
463
468
|
from omega_engine.provider_state import active_provider as _active_provider
|
|
464
469
|
|
|
470
|
+
# v0.19.39 — chat-first redesign. The TUI now opens on CONVERSATIONS
|
|
471
|
+
# (live tmux sessions: AISB chat, Hermès chat, active Oracles per
|
|
472
|
+
# project, active Workers per task) with ●/○ status dots. Setup,
|
|
473
|
+
# config, infra, audits, scrape, etc. move into sub-menus opened from
|
|
474
|
+
# a short "MENU" section. Reasoning: the user spends 99% of their
|
|
475
|
+
# time in conversations — the menu should reflect that, not bury the
|
|
476
|
+
# chats below 6 sections of admin options.
|
|
477
|
+
DOT_ON = f"{AMBER}●{RST}" # alive
|
|
478
|
+
DOT_OFF = f"{MUTED}○{RST}" # not running
|
|
479
|
+
|
|
480
|
+
def _dot(alive: bool) -> str:
|
|
481
|
+
return DOT_ON if alive else DOT_OFF
|
|
482
|
+
|
|
483
|
+
def _conv_label(name: str, hint: str, alive: bool) -> str:
|
|
484
|
+
"""Conversation row: `<dot> <name> <dim hint>`."""
|
|
485
|
+
dot = _dot(alive)
|
|
486
|
+
return f" {dot} {name:<32}{DIM}{hint}{RST}"
|
|
487
|
+
|
|
488
|
+
def _paperclip_status_quick() -> tuple[bool, str]:
|
|
489
|
+
"""Lightweight inline Paperclip probe — short timeout, no raise.
|
|
490
|
+
Returns (alive, hint). Hint is empty when down, ``localhost:8080``
|
|
491
|
+
(or whatever port the bridge reports) when up. Uses the new
|
|
492
|
+
``paperclip_bridge.is_running()`` from chantier 4 when present;
|
|
493
|
+
falls back gracefully to a plain TCP probe.
|
|
494
|
+
"""
|
|
495
|
+
try:
|
|
496
|
+
from omega_engine.paperclip_bridge import is_running as _pcst
|
|
497
|
+
st = _pcst(HOME)
|
|
498
|
+
if getattr(st, "running", False):
|
|
499
|
+
port = getattr(st, "port", None) or 8080
|
|
500
|
+
return True, f"localhost:{port}"
|
|
501
|
+
except Exception: # noqa: BLE001
|
|
502
|
+
# Fallback: a 200ms TCP probe to 127.0.0.1:8080.
|
|
503
|
+
import socket as _s
|
|
504
|
+
try:
|
|
505
|
+
with _s.create_connection(("127.0.0.1", 8080), timeout=0.2):
|
|
506
|
+
return True, "localhost:8080"
|
|
507
|
+
except OSError:
|
|
508
|
+
pass
|
|
509
|
+
return False, ""
|
|
510
|
+
|
|
511
|
+
def _active_oracles_and_workers() -> tuple[list, list]:
|
|
512
|
+
"""Categorize live tmux sessions into (oracles, workers).
|
|
513
|
+
Each entry is the ``TmuxSession`` instance."""
|
|
514
|
+
all_sessions = tmux.list_sessions(HOME)
|
|
515
|
+
oracles = sorted([s for s in all_sessions if s.category == "oracle"],
|
|
516
|
+
key=lambda x: x.name)
|
|
517
|
+
workers = sorted([s for s in all_sessions if s.category == "worker"],
|
|
518
|
+
key=lambda x: x.name)
|
|
519
|
+
return oracles, workers
|
|
520
|
+
|
|
465
521
|
def _build_items() -> list[tuple[str, str]]:
|
|
466
|
-
"""Return (display, action_key) — section headers have key '__sep__'.
|
|
522
|
+
"""Return (display, action_key) — section headers have key '__sep__'.
|
|
523
|
+
|
|
524
|
+
v0.19.39 layout (chat-first):
|
|
525
|
+
1. CONVERSATIONS — AISB / Hermès / live Oracles / live Workers
|
|
526
|
+
2. QUICK ACTIONS — new chat, new project, run mission, Paperclip
|
|
527
|
+
3. MENU — sub-menus (audits, setup, infra, health)
|
|
528
|
+
4. EXIT
|
|
529
|
+
"""
|
|
467
530
|
provider = _active_provider()
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
(
|
|
484
|
-
|
|
485
|
-
(
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
("",
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
531
|
+
aisb_alive = tmux.omega_window_alive("aisb")
|
|
532
|
+
hermes_alive = tmux.omega_window_alive("hermes")
|
|
533
|
+
oracles, workers = _active_oracles_and_workers()
|
|
534
|
+
paperclip_alive, paperclip_hint = _paperclip_status_quick()
|
|
535
|
+
|
|
536
|
+
items: list[tuple[str, str]] = []
|
|
537
|
+
|
|
538
|
+
# ── CONVERSATIONS ───────────────────────────────────────────────
|
|
539
|
+
items.append((_section("CONVERSATIONS"), "__sep__"))
|
|
540
|
+
items.append((_conv_label("AISB master", "claude (Max OAuth)", aisb_alive), "open:aisb"))
|
|
541
|
+
items.append((_conv_label("Hermès", "claude (Anthropic API)", hermes_alive), "open:hermes"))
|
|
542
|
+
|
|
543
|
+
# Per-project live oracles + workers (only when there are any —
|
|
544
|
+
# don't waste a row when the user has nothing running).
|
|
545
|
+
if oracles or workers:
|
|
546
|
+
items.append(("", "__sep__"))
|
|
547
|
+
if oracles:
|
|
548
|
+
items.append((f" {DIM}— Active Oracles ({len(oracles)}) —{RST}", "__sep__"))
|
|
549
|
+
for s in oracles:
|
|
550
|
+
proj = s.project or "?"
|
|
551
|
+
hint = f"project: {proj}"
|
|
552
|
+
items.append((_conv_label(s.name, hint, True), f"attach:{s.name}"))
|
|
553
|
+
if workers:
|
|
554
|
+
items.append((f" {DIM}— Active Workers ({len(workers)}) —{RST}", "__sep__"))
|
|
555
|
+
for s in workers:
|
|
556
|
+
# Extract task from `<proj>-worker-N-<task>`.
|
|
557
|
+
task = s.name.split("worker-", 1)[-1].split("-", 1)[-1] if "worker-" in s.name else "?"
|
|
558
|
+
hint = f"task: {task}"
|
|
559
|
+
items.append((_conv_label(s.name, hint, True), f"attach:{s.name}"))
|
|
560
|
+
|
|
561
|
+
items.append(("", "__sep__"))
|
|
562
|
+
|
|
563
|
+
# ── QUICK ACTIONS ───────────────────────────────────────────────
|
|
564
|
+
items.append((_section("QUICK ACTIONS"), "__sep__"))
|
|
565
|
+
items.append((_label("+ New AISB chat", "fresh session"), "open:aisb:new"))
|
|
566
|
+
items.append((_label("+ New Hermès chat", "fresh session"), "open:hermes:new"))
|
|
567
|
+
items.append((_label("+ New project", "Genesis pipeline"), "genesis:new"))
|
|
568
|
+
items.append((_label("Run a mission", "verified completion"), "run:mission"))
|
|
569
|
+
# Paperclip dashboard with live status indicator.
|
|
570
|
+
pclbl = f"Paperclip dashboard"
|
|
571
|
+
pcdot = _dot(paperclip_alive)
|
|
572
|
+
pchint = paperclip_hint if paperclip_alive else "not running"
|
|
573
|
+
items.append((f" {pcdot} {pclbl:<32}{DIM}{pchint}{RST}", "paperclip:dashboard"))
|
|
574
|
+
|
|
575
|
+
items.append(("", "__sep__"))
|
|
576
|
+
|
|
577
|
+
# ── MENU (sub-menus for everything else) ────────────────────────
|
|
578
|
+
items.append((_section("MENU"), "__sep__"))
|
|
579
|
+
items.append((_label("Quality Arsenal", "17 forensic audits"), "submenu:audits"))
|
|
580
|
+
items.append((_label("Setup & config", f"LLM: {provider}"), "submenu:setup"))
|
|
581
|
+
items.append((_label("Infrastructure", "sessions, scrape"), "submenu:infra"))
|
|
582
|
+
items.append((_label("Health checks", "doctor, status"), "submenu:health"))
|
|
583
|
+
items.append((_label("Paperclip governance", "register, status"), "submenu:paperclip"))
|
|
584
|
+
|
|
585
|
+
items.append(("", "__sep__"))
|
|
586
|
+
|
|
587
|
+
# ── EXIT ────────────────────────────────────────────────────────
|
|
588
|
+
items.append((_section("EXIT"), "__sep__"))
|
|
589
|
+
items.append((_label("Detach", "session keeps running"), "detach"))
|
|
590
|
+
items.append((_label("Quit Omega", "kills the tmux session"), "quit:kill"))
|
|
591
|
+
|
|
592
|
+
return items
|
|
593
|
+
|
|
594
|
+
def _submenu_items(name: str) -> list[tuple[str, str]]:
|
|
595
|
+
"""Return (display, action_key) for one of the named sub-menus.
|
|
596
|
+
Every sub-menu ends with a synthetic '← back' row that aborts the
|
|
597
|
+
cascaded fzf with key 'back'."""
|
|
598
|
+
if name == "audits":
|
|
599
|
+
return [
|
|
600
|
+
(_section("QUALITY ARSENAL"), "__sep__"),
|
|
601
|
+
(_label("List all 17 audits"), "audit:menu"),
|
|
602
|
+
(_label("Run an audit", "interactive"), "audit:run"),
|
|
603
|
+
("", "__sep__"),
|
|
604
|
+
(_label("← back"), "back"),
|
|
605
|
+
]
|
|
606
|
+
if name == "setup":
|
|
607
|
+
return [
|
|
608
|
+
(_section("SETUP & CONFIG"), "__sep__"),
|
|
609
|
+
(_label("Switch LLM provider"), "switch:provider"),
|
|
610
|
+
(_label("Accounts", "Claude Max pool"), "accounts:menu"),
|
|
611
|
+
(_label("Vault", "encrypted secrets"), "vault:menu"),
|
|
612
|
+
("", "__sep__"),
|
|
613
|
+
(_label("← back"), "back"),
|
|
614
|
+
]
|
|
615
|
+
if name == "infra":
|
|
616
|
+
return [
|
|
617
|
+
(_section("INFRASTRUCTURE"), "__sep__"),
|
|
618
|
+
(_label("List tmux sessions"), "sessions:list"),
|
|
619
|
+
(_label("Open project shell"), "project:open"),
|
|
620
|
+
("", "__sep__"),
|
|
621
|
+
(_label("Stealth scrape", "CloakBrowser"), "scrape:cloak"),
|
|
622
|
+
(_label("Fast scrape", "Scrapling"), "scrape:scrapling"),
|
|
623
|
+
("", "__sep__"),
|
|
624
|
+
(_label("← back"), "back"),
|
|
625
|
+
]
|
|
626
|
+
if name == "health":
|
|
627
|
+
return [
|
|
628
|
+
(_section("HEALTH"), "__sep__"),
|
|
629
|
+
(_label("omega doctor", "full health check"), "cmd:doctor"),
|
|
630
|
+
(_label("omega status", "task state"), "cmd:status"),
|
|
631
|
+
("", "__sep__"),
|
|
632
|
+
(_label("← back"), "back"),
|
|
633
|
+
]
|
|
634
|
+
if name == "paperclip":
|
|
635
|
+
return [
|
|
636
|
+
(_section("PAPERCLIP GOVERNANCE (L0)"), "__sep__"),
|
|
637
|
+
(_label("Open dashboard"), "paperclip:dashboard"),
|
|
638
|
+
(_label("Status", "bridge health"), "paperclip:status"),
|
|
639
|
+
(_label("Register", "(re)sync OmegaOS company"), "paperclip:register"),
|
|
640
|
+
("", "__sep__"),
|
|
641
|
+
(_label("← back"), "back"),
|
|
642
|
+
]
|
|
643
|
+
return [(_label("← back"), "back")]
|
|
505
644
|
|
|
506
645
|
def _run_inline(cmd_argv, *, shell: bool = False) -> None:
|
|
507
646
|
os.system("clear")
|
|
@@ -525,23 +664,29 @@ def _arrow_menu() -> int:
|
|
|
525
664
|
except (EOFError, KeyboardInterrupt):
|
|
526
665
|
return ""
|
|
527
666
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
667
|
+
def _pick(items: list[tuple[str, str]],
|
|
668
|
+
header_extra: str = "") -> str | None:
|
|
669
|
+
"""Render one fzf pass over ``items`` and return the chosen
|
|
670
|
+
action key (the second element of the picked tuple), or ``None``
|
|
671
|
+
on Esc / Ctrl-C / error.
|
|
672
|
+
|
|
673
|
+
Skips section headers and blank rows automatically — the caller
|
|
674
|
+
never has to worry about ``__sep__`` picks.
|
|
675
|
+
|
|
676
|
+
v0.19.37 lock-in: input is tab-delimited ``<idx>\\t<display>``,
|
|
677
|
+
fzf --with-nth=2.. shows only the visual column, and we parse
|
|
678
|
+
the index column out of stdout — survives any ANSI/whitespace
|
|
679
|
+
transformation fzf applies.
|
|
680
|
+
"""
|
|
538
681
|
lines = []
|
|
539
|
-
for i, (disp,
|
|
682
|
+
for i, (disp, _key) in enumerate(items):
|
|
540
683
|
lines.append(f"{i}\t{disp}")
|
|
541
684
|
header = (
|
|
542
685
|
f"{ORANGE}{BOLD}Ω Omega OS v{__version__}{RST} "
|
|
543
686
|
f"{MUTED}• ↑↓ navigate • ↵ pick • / search • Esc refresh{RST}"
|
|
544
687
|
)
|
|
688
|
+
if header_extra:
|
|
689
|
+
header = f"{header}\n{MUTED}{header_extra}{RST}"
|
|
545
690
|
try:
|
|
546
691
|
proc = subprocess.run(
|
|
547
692
|
["fzf",
|
|
@@ -560,44 +705,67 @@ def _arrow_menu() -> int:
|
|
|
560
705
|
"--pointer=▶",
|
|
561
706
|
"--marker=●",
|
|
562
707
|
"--color="
|
|
563
|
-
"bg
|
|
564
|
-
"fg
|
|
565
|
-
"bg+:#
|
|
566
|
-
"fg
|
|
567
|
-
"hl
|
|
568
|
-
"hl
|
|
569
|
-
"prompt
|
|
570
|
-
"pointer
|
|
571
|
-
"marker
|
|
572
|
-
"header
|
|
573
|
-
"border
|
|
574
|
-
"info
|
|
575
|
-
"spinner
|
|
576
|
-
"gutter
|
|
708
|
+
"bg:-1,"
|
|
709
|
+
"fg:default,"
|
|
710
|
+
"bg+:#1c1c1c,"
|
|
711
|
+
"fg+:colour215,"
|
|
712
|
+
"hl:colour137,"
|
|
713
|
+
"hl+:colour215,"
|
|
714
|
+
"prompt:colour137,"
|
|
715
|
+
"pointer:colour137,"
|
|
716
|
+
"marker:colour215,"
|
|
717
|
+
"header:colour137,"
|
|
718
|
+
"border:colour137,"
|
|
719
|
+
"info:colour137,"
|
|
720
|
+
"spinner:colour137,"
|
|
721
|
+
"gutter:-1"],
|
|
577
722
|
input="\n".join(lines), capture_output=True, text=True,
|
|
578
723
|
)
|
|
579
724
|
except (KeyboardInterrupt, subprocess.SubprocessError):
|
|
580
|
-
return
|
|
725
|
+
return None
|
|
581
726
|
if proc.returncode != 0:
|
|
582
|
-
|
|
583
|
-
continue
|
|
727
|
+
return None
|
|
584
728
|
pick = proc.stdout.rstrip("\n")
|
|
585
|
-
# Parse the index column. The tab is always the first \t in the
|
|
586
|
-
# picked line (the rest of the display may contain colour codes
|
|
587
|
-
# but no tabs).
|
|
588
729
|
if "\t" not in pick:
|
|
589
|
-
|
|
590
|
-
idx_str,
|
|
730
|
+
return None
|
|
731
|
+
idx_str, _ = pick.split("\t", 1)
|
|
591
732
|
try:
|
|
592
733
|
idx = int(idx_str)
|
|
593
734
|
except ValueError:
|
|
594
|
-
|
|
735
|
+
return None
|
|
595
736
|
if not (0 <= idx < len(items)):
|
|
596
|
-
|
|
737
|
+
return None
|
|
597
738
|
action = items[idx][1]
|
|
598
739
|
if action == "__sep__":
|
|
599
|
-
|
|
740
|
+
return None
|
|
741
|
+
return action
|
|
742
|
+
|
|
743
|
+
def _open_submenu(name: str) -> str | None:
|
|
744
|
+
"""Render a sub-menu in a loop until the user picks an action OR
|
|
745
|
+
chooses 'back'. Returns the action key to dispatch (the caller
|
|
746
|
+
runs it), or None when the user backs out / Esc'd.
|
|
747
|
+
"""
|
|
748
|
+
while True:
|
|
749
|
+
sub_items = _submenu_items(name)
|
|
750
|
+
picked = _pick(sub_items, header_extra=f"sub-menu: {name} · Esc/← back to main")
|
|
751
|
+
if picked is None or picked == "back":
|
|
752
|
+
return None
|
|
753
|
+
return picked
|
|
754
|
+
|
|
755
|
+
while True:
|
|
756
|
+
items = _build_items()
|
|
757
|
+
action = _pick(items)
|
|
758
|
+
if action is None:
|
|
759
|
+
# Esc → just refresh the conversations panel (cheap — re-renders
|
|
760
|
+
# with live tmux state).
|
|
600
761
|
continue
|
|
762
|
+
# Sub-menu indirection: when the user picks a sub-menu, render it
|
|
763
|
+
# in its own loop until they pick a real action or back out.
|
|
764
|
+
if action.startswith("submenu:"):
|
|
765
|
+
sub_name = action.split(":", 1)[1]
|
|
766
|
+
action = _open_submenu(sub_name)
|
|
767
|
+
if action is None:
|
|
768
|
+
continue
|
|
601
769
|
|
|
602
770
|
# === Dispatch ===
|
|
603
771
|
if action == "detach":
|
|
@@ -606,19 +774,50 @@ def _arrow_menu() -> int:
|
|
|
606
774
|
if action == "quit:kill":
|
|
607
775
|
subprocess.run(["tmux", "kill-session", "-t", "Omega"])
|
|
608
776
|
return 0
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
777
|
+
# v0.19.39 — attach to a live Oracle / Worker tmux session. The
|
|
778
|
+
# menu lists them as `attach:<session_name>`. We use
|
|
779
|
+
# `select-window` when the session is already a window inside
|
|
780
|
+
# Omega; otherwise we switch the client to that session.
|
|
781
|
+
if action.startswith("attach:"):
|
|
782
|
+
target = action.split(":", 1)[1]
|
|
783
|
+
# If the target is a window of Omega, just select it. Else
|
|
784
|
+
# switch-client to that session (works under nested tmux).
|
|
785
|
+
wnames = subprocess.run(
|
|
786
|
+
["tmux", "list-windows", "-t", "Omega", "-F", "#W"],
|
|
787
|
+
capture_output=True, text=True,
|
|
788
|
+
)
|
|
789
|
+
if (wnames.returncode == 0
|
|
790
|
+
and target in (wnames.stdout or "").splitlines()):
|
|
791
|
+
subprocess.run(["tmux", "select-window",
|
|
792
|
+
"-t", f"Omega:{target}"])
|
|
793
|
+
else:
|
|
794
|
+
# Switch to the foreign session. Use switch-client (works
|
|
795
|
+
# when we're already inside a tmux client) or fall back to
|
|
796
|
+
# attach for non-tmux contexts.
|
|
797
|
+
rc = subprocess.run(
|
|
798
|
+
["tmux", "switch-client", "-t", target],
|
|
799
|
+
capture_output=True,
|
|
800
|
+
).returncode
|
|
801
|
+
if rc != 0:
|
|
802
|
+
_run_inline(f"echo ' cannot attach to {target} — is it alive?' "
|
|
803
|
+
f"&& tmux has-session -t {target} && "
|
|
804
|
+
f"echo ' tmux says: yes' || echo ' tmux says: no'",
|
|
805
|
+
shell=True)
|
|
806
|
+
continue
|
|
807
|
+
# v0.19.39 — "+ New" actions: kill existing chat window first so
|
|
808
|
+
# the user gets a clean fresh session.
|
|
809
|
+
if action in ("open:aisb", "open:aisb:new"):
|
|
810
|
+
force = (action == "open:aisb:new")
|
|
613
811
|
persona = HOME / "Agentik_SSOT" / "agents" / "aisb" / "CLAUDE.md"
|
|
614
812
|
ctx_dir = tmux._ensure_chat_context_dir(HOME, "aisb-master", persona)
|
|
615
813
|
tmux.spawn_chat_in_omega(
|
|
616
814
|
"aisb", ctx_dir=ctx_dir, run_command="claude",
|
|
617
|
-
force_replace=
|
|
815
|
+
force_replace=force,
|
|
618
816
|
)
|
|
619
817
|
subprocess.run(["tmux", "select-window", "-t", "Omega:aisb"])
|
|
620
818
|
continue
|
|
621
|
-
if action
|
|
819
|
+
if action in ("open:hermes", "open:hermes:new"):
|
|
820
|
+
force = (action == "open:hermes:new")
|
|
622
821
|
persona = HOME / "Agentik_SSOT" / "docs" / "LAYERS.md"
|
|
623
822
|
ctx_dir = tmux._ensure_chat_context_dir(HOME, "hermes", persona)
|
|
624
823
|
try:
|
|
@@ -632,10 +831,18 @@ def _arrow_menu() -> int:
|
|
|
632
831
|
if api_key else "claude")
|
|
633
832
|
tmux.spawn_chat_in_omega(
|
|
634
833
|
"hermes", ctx_dir=ctx_dir, run_command=run_cmd,
|
|
635
|
-
force_replace=
|
|
834
|
+
force_replace=force,
|
|
636
835
|
)
|
|
637
836
|
subprocess.run(["tmux", "select-window", "-t", "Omega:hermes"])
|
|
638
837
|
continue
|
|
838
|
+
if action == "audit:run":
|
|
839
|
+
audit_id = _prompt("audit id (codeaudit, uiuxaudit, flowaudit, ...)")
|
|
840
|
+
if audit_id:
|
|
841
|
+
_run_inline([OMEGA_BIN, "audit", audit_id])
|
|
842
|
+
continue
|
|
843
|
+
# (v0.19.31 open:aisb / open:hermes legacy handlers removed in
|
|
844
|
+
# v0.19.39 — the new unified handlers above (which accept both
|
|
845
|
+
# plain and `:new` variants) cover the same surface.)
|
|
639
846
|
if action == "switch:provider":
|
|
640
847
|
_run_inline([OMEGA_BIN, "switch"]); continue
|
|
641
848
|
if action == "genesis:new":
|
|
Binary file
|
|
Binary file
|
package/omega/Agentik_Engine/tests/__pycache__/test_paperclip_status.cpython-313-pytest-8.4.2.pyc
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/omega/Agentik_Engine/tests/__pycache__/test_tui_runtime.cpython-313-pytest-8.4.2.pyc
CHANGED
|
Binary file
|
|
Binary file
|