@agentikos/omega-os 0.19.34 → 0.19.36
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 +65 -0
- package/install.sh +74 -21
- 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__/provider_state.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 +8 -22
- package/omega/Agentik_Engine/omega_engine/provider_state.py +42 -0
- package/omega/Agentik_Engine/omega_engine/tui.py +6 -0
- package/omega/Agentik_Engine/pyproject.toml +1 -1
- 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_tui_runtime.py +104 -0
- package/omega/Agentik_SSOT/VERSION +1 -1
- package/package.json +1 -1
package/bootstrap/lib/common.sh
CHANGED
|
@@ -75,12 +75,45 @@ record_state_version() {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
# run_step <name> <function>
|
|
78
|
+
#
|
|
79
|
+
# In NORMAL mode: prints `:: step <name>` headers + step output flows
|
|
80
|
+
# to the terminal in real time (the v0.19.34 behaviour).
|
|
81
|
+
#
|
|
82
|
+
# In FULL mode (INSTALL_FULL=1, set by `--full`): redirects each step's
|
|
83
|
+
# stdout+stderr to $LOG_FILE and updates a single progress bar line
|
|
84
|
+
# instead. No `:: step xx` chatter. Operator sees:
|
|
85
|
+
#
|
|
86
|
+
# Installing… ████████████░░░░░░░░░░ 14/21 66% 45-claude-plugins
|
|
87
|
+
#
|
|
88
|
+
# When the run finishes, the progress bar clears and the post-install
|
|
89
|
+
# card prints normally.
|
|
78
90
|
run_step() {
|
|
79
91
|
local name="$1" fn="$2"
|
|
80
92
|
if step_done "$name" && [ "${FORCE:-0}" != "1" ]; then
|
|
93
|
+
if [ "${INSTALL_FULL:-0}" = "1" ]; then
|
|
94
|
+
_full_progress "$name" "skip"
|
|
95
|
+
return 0
|
|
96
|
+
fi
|
|
81
97
|
log "${C_DIM}-- skip $name (already done)${C_RST}"
|
|
82
98
|
return 0
|
|
83
99
|
fi
|
|
100
|
+
|
|
101
|
+
if [ "${INSTALL_FULL:-0}" = "1" ]; then
|
|
102
|
+
# Redirect step output to the log; only the progress bar stays on screen.
|
|
103
|
+
_full_progress "$name" "run"
|
|
104
|
+
if "$fn" >>"$LOG_FILE" 2>&1; then
|
|
105
|
+
mark_done "$name"
|
|
106
|
+
_full_progress "$name" "ok"
|
|
107
|
+
else
|
|
108
|
+
# Clear the bar then surface the error inline.
|
|
109
|
+
printf "\r\033[K"
|
|
110
|
+
err "step $name failed — see $LOG_FILE"
|
|
111
|
+
die "step $name failed — fix the cause and re-run install.sh"
|
|
112
|
+
fi
|
|
113
|
+
return 0
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
# Normal verbose mode (default).
|
|
84
117
|
info "step $name"
|
|
85
118
|
if "$fn"; then
|
|
86
119
|
mark_done "$name"
|
|
@@ -90,6 +123,38 @@ run_step() {
|
|
|
90
123
|
fi
|
|
91
124
|
}
|
|
92
125
|
|
|
126
|
+
# _full_progress <step_name> <phase=run|ok|skip>
|
|
127
|
+
# Renders one line: "Installing… <bar> N/M % <current step>"
|
|
128
|
+
# Uses \r to overwrite — no scrollback noise.
|
|
129
|
+
_full_progress() {
|
|
130
|
+
local step="$1" phase="$2"
|
|
131
|
+
STEP_COUNT=$((${STEP_COUNT:-0} + 1))
|
|
132
|
+
local total="${STEP_TOTAL:-21}"
|
|
133
|
+
local current="$STEP_COUNT"
|
|
134
|
+
# Decrement displayed count for "skip" so the bar represents real progress
|
|
135
|
+
if [ "$phase" = "skip" ]; then
|
|
136
|
+
: # leave count as-is; skips still count as progress
|
|
137
|
+
fi
|
|
138
|
+
local pct=$((current * 100 / total))
|
|
139
|
+
local bar_width=30
|
|
140
|
+
local filled=$((current * bar_width / total))
|
|
141
|
+
local empty=$((bar_width - filled))
|
|
142
|
+
local bar=""
|
|
143
|
+
if [ "$filled" -gt 0 ]; then
|
|
144
|
+
bar="$(printf '█%.0s' $(seq 1 "$filled"))"
|
|
145
|
+
fi
|
|
146
|
+
if [ "$empty" -gt 0 ]; then
|
|
147
|
+
bar="${bar}$(printf '░%.0s' $(seq 1 "$empty"))"
|
|
148
|
+
fi
|
|
149
|
+
# \033[K clears to end of line so the previous step name doesn't bleed.
|
|
150
|
+
printf "\r ${C_ORANGE}Installing…${C_RST} ${bar} ${C_BOLD}%2d/%d${C_RST} %3d%% ${C_DIM}%-32s${C_RST}\033[K" \
|
|
151
|
+
"$current" "$total" "$pct" "$step"
|
|
152
|
+
# Final newline only when we hit the last step.
|
|
153
|
+
if [ "$current" -ge "$total" ]; then
|
|
154
|
+
printf "\n"
|
|
155
|
+
fi
|
|
156
|
+
}
|
|
157
|
+
|
|
93
158
|
# --- user resolution ---------------------------------------------------------
|
|
94
159
|
#
|
|
95
160
|
# The installer is modular about WHICH user it runs as. Three modes, decided
|
package/install.sh
CHANGED
|
@@ -25,6 +25,7 @@ source "$REPO_DIR/bootstrap/lib/steps.sh"
|
|
|
25
25
|
PROFILE="vps"; MANIFEST=""; NONINTERACTIVE=0; FORCE=0
|
|
26
26
|
USER_REQUESTED=""; CREATE_USER=0; CREATE_USER_NAME=""
|
|
27
27
|
PROFILE_EXPLICIT=0; NO_PATH_SETUP=0; DRY_RUN=0
|
|
28
|
+
INSTALL_FULL=0; FULL_WANT_TELEGRAM=""
|
|
28
29
|
[ "$(uname -s)" = "Darwin" ] && PROFILE="workstation"
|
|
29
30
|
|
|
30
31
|
while [ $# -gt 0 ]; do
|
|
@@ -41,6 +42,14 @@ while [ $# -gt 0 ]; do
|
|
|
41
42
|
--force) FORCE=1; shift ;;
|
|
42
43
|
--no-path-setup) NO_PATH_SETUP=1; shift ;;
|
|
43
44
|
--dry-run) DRY_RUN=1; shift ;;
|
|
45
|
+
# `--full` — silent full-recommended install. One prompt
|
|
46
|
+
# (Telegram yes/no), then progress bar only. Selects every
|
|
47
|
+
# recommended LLM CLI / MCP / Claude plugin / system CLI.
|
|
48
|
+
--full) INSTALL_FULL=1; NONINTERACTIVE=1; shift ;;
|
|
49
|
+
--full-no-telegram) INSTALL_FULL=1; NONINTERACTIVE=1
|
|
50
|
+
FULL_WANT_TELEGRAM=no; shift ;;
|
|
51
|
+
--full-with-telegram) INSTALL_FULL=1; NONINTERACTIVE=1
|
|
52
|
+
FULL_WANT_TELEGRAM=yes; shift ;;
|
|
44
53
|
--user) USER_REQUESTED="${2:?}"; shift 2 ;;
|
|
45
54
|
--create-user)
|
|
46
55
|
CREATE_USER=1
|
|
@@ -123,15 +132,41 @@ fi
|
|
|
123
132
|
|
|
124
133
|
# ───── UX header ─────
|
|
125
134
|
install_banner
|
|
126
|
-
|
|
135
|
+
# In --full mode skip the heavy preflight card; we'll show the progress
|
|
136
|
+
# bar instead. Banner still prints so the user sees "Omega OS vX.Y.Z".
|
|
137
|
+
if [ "${INSTALL_FULL:-0}" != "1" ]; then
|
|
138
|
+
preflight_card
|
|
139
|
+
fi
|
|
127
140
|
|
|
128
141
|
# Interactive profile picker if the operator did not pass --profile.
|
|
129
|
-
|
|
142
|
+
# (Skipped in --full mode — uses the default profile for the OS.)
|
|
143
|
+
if [ "${INSTALL_FULL:-0}" != "1" ]; then
|
|
144
|
+
pick_profile_interactive
|
|
145
|
+
fi
|
|
130
146
|
|
|
131
147
|
# Final pre-run summary (one tight line so the operator knows what they
|
|
132
|
-
# confirmed).
|
|
133
|
-
|
|
134
|
-
|
|
148
|
+
# confirmed). Skipped in --full mode.
|
|
149
|
+
if [ "${INSTALL_FULL:-0}" != "1" ]; then
|
|
150
|
+
log "${C_DIM}::${C_RST} starting install — profile=${C_BOLD}$PROFILE${C_RST} os=$OMEGA_OS user=$OMEGA_USER home=$OMEGA_HOME"
|
|
151
|
+
echo
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
# In --full mode we ask EXACTLY one question before anything else:
|
|
155
|
+
# "install Telegram?" If they pass --full-with-telegram or
|
|
156
|
+
# --full-no-telegram on the CLI, we skip even this prompt.
|
|
157
|
+
if [ "${INSTALL_FULL:-0}" = "1" ] && [ -z "${FULL_WANT_TELEGRAM:-}" ]; then
|
|
158
|
+
if [ -t 0 ] && [ "${NONINTERACTIVE:-0}" != "1" ]; then
|
|
159
|
+
if prompt_yes_no " Install the Telegram bot?" "no"; then
|
|
160
|
+
FULL_WANT_TELEGRAM=yes
|
|
161
|
+
else
|
|
162
|
+
FULL_WANT_TELEGRAM=no
|
|
163
|
+
fi
|
|
164
|
+
else
|
|
165
|
+
# Truly headless (piped stdin) — default to NO Telegram.
|
|
166
|
+
FULL_WANT_TELEGRAM=no
|
|
167
|
+
fi
|
|
168
|
+
echo
|
|
169
|
+
fi
|
|
135
170
|
|
|
136
171
|
# Define the sequence ONCE so we can count it for the progress header.
|
|
137
172
|
STEPS=(
|
|
@@ -157,7 +192,11 @@ STEPS=(
|
|
|
157
192
|
"45-claude-plugins:step_claude_plugins"
|
|
158
193
|
)
|
|
159
194
|
if [ "$PROFILE" != "minimal" ]; then
|
|
160
|
-
|
|
195
|
+
# In --full mode the Telegram step is gated by the single yes/no asked
|
|
196
|
+
# at the very top. Skip the step entirely when the user said no.
|
|
197
|
+
if [ "${INSTALL_FULL:-0}" != "1" ] || [ "${FULL_WANT_TELEGRAM:-}" != "no" ]; then
|
|
198
|
+
STEPS+=("50-telegram:step_telegram")
|
|
199
|
+
fi
|
|
161
200
|
fi
|
|
162
201
|
STEPS+=(
|
|
163
202
|
"55-autonomous:step_autonomous"
|
|
@@ -170,25 +209,27 @@ STEPS+=(
|
|
|
170
209
|
export STEP_TOTAL="${#STEPS[@]}"
|
|
171
210
|
export STEP_COUNT=0
|
|
172
211
|
|
|
173
|
-
# ───── Plan mode ─────
|
|
174
|
-
#
|
|
175
|
-
#
|
|
176
|
-
|
|
177
|
-
echo
|
|
178
|
-
log "${C_DIM}─── Install plan (${STEP_TOTAL} steps, ~2-3 min total) ───${C_RST}"
|
|
179
|
-
_idx=0
|
|
180
|
-
for entry in "${STEPS[@]}"; do
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
done
|
|
185
|
-
log "${C_DIM}─────────────────────────────────────────${C_RST}"
|
|
186
|
-
echo
|
|
212
|
+
# ───── Plan mode (verbose only) ─────
|
|
213
|
+
# In NORMAL mode: show every step BEFORE running + ask for confirmation.
|
|
214
|
+
# In --full mode: skip the plan — operator already opted in via the flag.
|
|
215
|
+
if [ "${INSTALL_FULL:-0}" != "1" ]; then
|
|
216
|
+
echo
|
|
217
|
+
log "${C_DIM}─── Install plan (${STEP_TOTAL} steps, ~2-3 min total) ───${C_RST}"
|
|
218
|
+
_idx=0
|
|
219
|
+
for entry in "${STEPS[@]}"; do
|
|
220
|
+
_idx=$((_idx + 1))
|
|
221
|
+
_name="${entry%%:*}"
|
|
222
|
+
log " ${C_DIM}${_idx}/${STEP_TOTAL}${C_RST} ${_name}"
|
|
223
|
+
done
|
|
224
|
+
log "${C_DIM}─────────────────────────────────────────${C_RST}"
|
|
225
|
+
echo
|
|
226
|
+
fi
|
|
187
227
|
|
|
188
228
|
if [ "${DRY_RUN:-0}" = "1" ]; then
|
|
189
229
|
ok "dry-run — exiting without running any step"
|
|
190
230
|
exit 0
|
|
191
231
|
fi
|
|
232
|
+
|
|
192
233
|
if [ "${NONINTERACTIVE:-0}" != "1" ] && [ -t 0 ]; then
|
|
193
234
|
if ! prompt_yes_no "Proceed with the install?" "yes"; then
|
|
194
235
|
log "aborted by operator — no changes made"
|
|
@@ -196,10 +237,22 @@ if [ "${NONINTERACTIVE:-0}" != "1" ] && [ -t 0 ]; then
|
|
|
196
237
|
fi
|
|
197
238
|
fi
|
|
198
239
|
|
|
240
|
+
# In --full mode, print the single header line that introduces the
|
|
241
|
+
# progress bar so the user knows what's happening.
|
|
242
|
+
if [ "${INSTALL_FULL:-0}" = "1" ]; then
|
|
243
|
+
echo
|
|
244
|
+
log " ${C_DIM}${STEP_TOTAL} steps · output piped to ${LOG_FILE} · Ctrl-c to abort${C_RST}"
|
|
245
|
+
echo
|
|
246
|
+
fi
|
|
247
|
+
|
|
199
248
|
for entry in "${STEPS[@]}"; do
|
|
200
249
|
name="${entry%%:*}"
|
|
201
250
|
fn="${entry##*:}"
|
|
202
|
-
|
|
251
|
+
# The verbose per-step header is suppressed in --full mode (progress
|
|
252
|
+
# bar replaces it).
|
|
253
|
+
if [ "${INSTALL_FULL:-0}" != "1" ]; then
|
|
254
|
+
step_progress_header "$name"
|
|
255
|
+
fi
|
|
203
256
|
run_step "$name" "$fn"
|
|
204
257
|
done
|
|
205
258
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -3147,28 +3147,14 @@ def cmd_menu_whiptail(_args: argparse.Namespace) -> int:
|
|
|
3147
3147
|
return run_menu()
|
|
3148
3148
|
|
|
3149
3149
|
|
|
3150
|
-
#
|
|
3151
|
-
#
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
return home / "Agentik_Extra" / "var" / _PROVIDER_MARKER
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
def _active_provider() -> str:
|
|
3162
|
-
p = _provider_state_path()
|
|
3163
|
-
if p.exists():
|
|
3164
|
-
return p.read_text().strip() or "claude_code"
|
|
3165
|
-
return "claude_code"
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
def _set_active_provider(provider_id: str) -> None:
|
|
3169
|
-
p = _provider_state_path()
|
|
3170
|
-
p.parent.mkdir(parents=True, exist_ok=True)
|
|
3171
|
-
p.write_text(provider_id.strip() + "\n")
|
|
3150
|
+
# Active LLM provider — now lives in omega_engine.provider_state so the
|
|
3151
|
+
# Textual TUI can read it without a circular cli↔tui import (v0.19.35 fix).
|
|
3152
|
+
from omega_engine.provider_state import (
|
|
3153
|
+
active_provider as _active_provider,
|
|
3154
|
+
set_active_provider as _set_active_provider,
|
|
3155
|
+
provider_state_path as _provider_state_path,
|
|
3156
|
+
PROVIDER_MARKER as _PROVIDER_MARKER,
|
|
3157
|
+
)
|
|
3172
3158
|
|
|
3173
3159
|
|
|
3174
3160
|
def cmd_paperclip(args: argparse.Namespace) -> int:
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Active-LLM-provider marker — shared between cli.py and tui.py.
|
|
2
|
+
|
|
3
|
+
The provider state lives in a tiny file at
|
|
4
|
+
``$OMEGA_HOME/Agentik_Extra/var/active-llm-provider``. `omega switch
|
|
5
|
+
<id>` writes here; the TUI and chat-spawn helpers read here.
|
|
6
|
+
|
|
7
|
+
Previously these helpers lived only in cli.py — but tui.py also needs
|
|
8
|
+
to read the active provider (to render `Switch LLM [current: claude_code]`
|
|
9
|
+
in the menu). Importing from cli would be circular (cli already imports
|
|
10
|
+
tui), so the helpers live here in their own neutral module.
|
|
11
|
+
"""
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import os
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
PROVIDER_MARKER = "active-llm-provider"
|
|
19
|
+
DEFAULT_PROVIDER = "claude_code"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _omega_home() -> Path:
|
|
23
|
+
return Path(os.environ.get("OMEGA_HOME", str(Path.home() / "Omega")))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def provider_state_path() -> Path:
|
|
27
|
+
return _omega_home() / "Agentik_Extra" / "var" / PROVIDER_MARKER
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def active_provider() -> str:
|
|
31
|
+
"""Read the active provider id, falling back to claude_code."""
|
|
32
|
+
p = provider_state_path()
|
|
33
|
+
if p.exists():
|
|
34
|
+
return p.read_text().strip() or DEFAULT_PROVIDER
|
|
35
|
+
return DEFAULT_PROVIDER
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def set_active_provider(provider_id: str) -> None:
|
|
39
|
+
"""Persist the active provider id atomically."""
|
|
40
|
+
p = provider_state_path()
|
|
41
|
+
p.parent.mkdir(parents=True, exist_ok=True)
|
|
42
|
+
p.write_text(provider_id.strip() + "\n")
|
|
@@ -456,6 +456,12 @@ def _arrow_menu() -> int:
|
|
|
456
456
|
def _section(name: str) -> str:
|
|
457
457
|
return f"{ORANGE}{BOLD}── {name} ──{RST}"
|
|
458
458
|
|
|
459
|
+
# `_active_provider` lived in cli.py until v0.19.34 — calling it from
|
|
460
|
+
# here NameError'd at runtime because cli isn't imported here (would
|
|
461
|
+
# be circular: cli already imports tui). Now lives in a neutral
|
|
462
|
+
# `omega_engine.provider_state` module both can read.
|
|
463
|
+
from omega_engine.provider_state import active_provider as _active_provider
|
|
464
|
+
|
|
459
465
|
def _build_items() -> list[tuple[str, str]]:
|
|
460
466
|
"""Return (display, action_key) — section headers have key '__sep__'."""
|
|
461
467
|
provider = _active_provider()
|
|
Binary file
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""Regression tests for omega_engine.tui — specifically the NameError
|
|
2
|
+
that escaped pure-import tests in v0.19.34.
|
|
3
|
+
|
|
4
|
+
v0.19.34's `_arrow_menu` referenced `_active_provider` (defined only in
|
|
5
|
+
cli.py) which failed with NameError when actually invoked, even though
|
|
6
|
+
`import omega_engine.tui` succeeded. Lesson: import-only smoke tests
|
|
7
|
+
don't catch undefined-name errors inside function bodies. These tests
|
|
8
|
+
exercise the function bodies enough to catch the same class of bug.
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import inspect
|
|
13
|
+
import os
|
|
14
|
+
import tempfile
|
|
15
|
+
import unittest
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TestTuiBodyResolves(unittest.TestCase):
|
|
20
|
+
"""Compile + exec the bodies of TUI functions to surface undefined
|
|
21
|
+
names. Pytest's normal collection only imports modules — it never
|
|
22
|
+
runs `_arrow_menu` itself."""
|
|
23
|
+
|
|
24
|
+
def test_arrow_menu_body_compiles(self):
|
|
25
|
+
from omega_engine.tui import _arrow_menu
|
|
26
|
+
src = inspect.getsource(_arrow_menu)
|
|
27
|
+
# If a referenced helper isn't importable from inside the
|
|
28
|
+
# function, this raises (catches v0.19.34's NameError class).
|
|
29
|
+
compile(src, "<test>", "exec")
|
|
30
|
+
|
|
31
|
+
def test_plain_repl_body_compiles(self):
|
|
32
|
+
from omega_engine.tui import _plain_repl
|
|
33
|
+
src = inspect.getsource(_plain_repl)
|
|
34
|
+
compile(src, "<test>", "exec")
|
|
35
|
+
|
|
36
|
+
def test_dispatch_slash_for_parse_only_commands(self):
|
|
37
|
+
"""Every documented slash command that doesn't shell out to the
|
|
38
|
+
omega binary must produce a CommandResult (no NameError, no
|
|
39
|
+
AttributeError). Commands that shell out (`/audit`, `/switch`,
|
|
40
|
+
`/doctor`, etc.) need the omega binary on disk — those are
|
|
41
|
+
smoke-tested separately on real installs."""
|
|
42
|
+
from omega_engine.tui import dispatch_slash
|
|
43
|
+
# These never shell out — pure dispatch.
|
|
44
|
+
cmds = [
|
|
45
|
+
"/help", "/quit", "/detach", "/unknown_xyz_command",
|
|
46
|
+
"/audit", # no args → static text only, no shell-out
|
|
47
|
+
]
|
|
48
|
+
for c in cmds:
|
|
49
|
+
r = dispatch_slash(c)
|
|
50
|
+
self.assertIsNotNone(r, f"dispatch_slash({c!r}) returned None")
|
|
51
|
+
self.assertTrue(
|
|
52
|
+
r.text or r.exit_tui or r.detach,
|
|
53
|
+
f"dispatch_slash({c!r}) returned empty result",
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class TestProviderStateSharedModule(unittest.TestCase):
|
|
58
|
+
"""The fix for v0.19.34's NameError was to extract the provider
|
|
59
|
+
state helpers into omega_engine.provider_state. Lock that in."""
|
|
60
|
+
|
|
61
|
+
def test_provider_state_module_exposes_helpers(self):
|
|
62
|
+
from omega_engine import provider_state as PS
|
|
63
|
+
for name in (
|
|
64
|
+
"active_provider", "set_active_provider",
|
|
65
|
+
"provider_state_path", "PROVIDER_MARKER", "DEFAULT_PROVIDER",
|
|
66
|
+
):
|
|
67
|
+
self.assertTrue(hasattr(PS, name),
|
|
68
|
+
f"provider_state.{name} missing — TUI + CLI rely on it")
|
|
69
|
+
|
|
70
|
+
def test_get_set_roundtrip(self):
|
|
71
|
+
from omega_engine.provider_state import (
|
|
72
|
+
active_provider, set_active_provider,
|
|
73
|
+
)
|
|
74
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
75
|
+
old_home = os.environ.get("OMEGA_HOME")
|
|
76
|
+
os.environ["OMEGA_HOME"] = tmp
|
|
77
|
+
try:
|
|
78
|
+
# Default before any set
|
|
79
|
+
self.assertEqual(active_provider(), "claude_code")
|
|
80
|
+
# Set + read
|
|
81
|
+
set_active_provider("gemini_cli")
|
|
82
|
+
self.assertEqual(active_provider(), "gemini_cli")
|
|
83
|
+
# Whitespace stripped
|
|
84
|
+
set_active_provider(" codex ")
|
|
85
|
+
self.assertEqual(active_provider(), "codex")
|
|
86
|
+
finally:
|
|
87
|
+
if old_home is None:
|
|
88
|
+
os.environ.pop("OMEGA_HOME", None)
|
|
89
|
+
else:
|
|
90
|
+
os.environ["OMEGA_HOME"] = old_home
|
|
91
|
+
|
|
92
|
+
def test_cli_imports_from_provider_state(self):
|
|
93
|
+
"""The cli.py local `_active_provider` must be re-exported from
|
|
94
|
+
provider_state — not a divergent definition (the bug was that
|
|
95
|
+
cli.py owned the definition and tui.py couldn't see it)."""
|
|
96
|
+
from omega_engine import cli, provider_state
|
|
97
|
+
self.assertIs(cli._active_provider, provider_state.active_provider,
|
|
98
|
+
"cli._active_provider must alias provider_state.active_provider")
|
|
99
|
+
self.assertIs(cli._set_active_provider,
|
|
100
|
+
provider_state.set_active_provider)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
if __name__ == "__main__":
|
|
104
|
+
unittest.main()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.19.
|
|
1
|
+
0.19.36
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentikos/omega-os",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.36",
|
|
4
4
|
"description": "Omega OS — installable agentic operating system with verified-completion orchestration. Event-sourced engine, 8-block rack, autonomous agents, MCP.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"omega-os": "bin/omega-os.js"
|