@agentikos/omega-os 0.19.41 → 0.19.43
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/__pycache__/llm-clis.cpython-313.pyc +0 -0
- package/bootstrap/lib/common.sh +6 -0
- package/bootstrap/lib/llm-clis.py +6 -0
- package/bootstrap/lib/manifest-helpers.py +110 -0
- package/bootstrap/lib/steps.sh +230 -26
- package/bootstrap/templates/aisb/CLAUDE.md +13 -0
- package/install.sh +8 -2
- 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__/hermes.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__/personas.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/provider.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 +44 -7
- package/omega/Agentik_Engine/omega_engine/hermes.py +43 -1
- package/omega/Agentik_Engine/omega_engine/paperclip_bridge.py +22 -0
- package/omega/Agentik_Engine/omega_engine/personas.py +11 -3
- package/omega/Agentik_Engine/omega_engine/provider.py +18 -3
- package/omega/Agentik_Engine/omega_engine/tmux.py +192 -42
- package/omega/Agentik_Engine/omega_engine/tui.py +8 -7
- package/omega/Agentik_Engine/pyproject.toml +1 -1
- package/omega/Agentik_Engine/tests/__pycache__/test_install_steps_v0_19_43.cpython-313-pytest-8.4.2.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_install_steps_v0_19_43.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_installer_wiring.cpython-313-pytest-8.4.2.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_installer_wiring.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_v19_43_fixes.cpython-313-pytest-8.4.2.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_v19_43_fixes.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/tests/test_install_steps_v0_19_43.py +242 -0
- package/omega/Agentik_Engine/tests/test_installer_wiring.py +128 -1
- package/omega/Agentik_Engine/tests/test_tmux_palette.py +158 -0
- package/omega/Agentik_Engine/tests/test_v19_43_fixes.py +265 -0
- package/omega/Agentik_SSOT/VERSION +1 -1
- package/omega/Agentik_SSOT/docs/AUDIT-V0.19.43.md +92 -0
- package/omega/Agentik_SSOT/rules/audit-gates.md +2 -2
- package/omega/Agentik_SSOT/rules/constitution.md +18 -0
- package/omega/Agentik_SSOT/rules/three-laws.md +2 -0
- package/package.json +1 -1
|
Binary file
|
package/bootstrap/lib/common.sh
CHANGED
|
@@ -37,8 +37,14 @@ detect_os() {
|
|
|
37
37
|
*) die "unsupported OS: $(uname -s)" ;;
|
|
38
38
|
esac
|
|
39
39
|
if [ "$OMEGA_OS" = "linux" ]; then
|
|
40
|
+
# Order matters: prefer the manager actually managing the distro.
|
|
41
|
+
# apt (Debian/Ubuntu) → dnf (RHEL/Fedora) → pacman (Arch/Manjaro)
|
|
42
|
+
# → apk (Alpine) → zypper (openSUSE/SLES) → unknown.
|
|
40
43
|
if have apt-get; then OMEGA_PKG="apt"
|
|
41
44
|
elif have dnf; then OMEGA_PKG="dnf"
|
|
45
|
+
elif have pacman; then OMEGA_PKG="pacman"
|
|
46
|
+
elif have apk; then OMEGA_PKG="apk"
|
|
47
|
+
elif have zypper; then OMEGA_PKG="zypper"
|
|
42
48
|
else OMEGA_PKG="unknown"; fi
|
|
43
49
|
else
|
|
44
50
|
OMEGA_PKG="brew"
|
|
@@ -219,6 +219,12 @@ def _resolve_install_cmd(spec: CliSpec) -> list[str] | None:
|
|
|
219
219
|
if _have("pip"):
|
|
220
220
|
return ["pip", "install", "--user", "aider-chat"]
|
|
221
221
|
return None
|
|
222
|
+
if spec.id == "ollama":
|
|
223
|
+
# Ollama's official installer is a curl-piped shell script —
|
|
224
|
+
# the only supported install path on Linux/macOS. v0.19.43 fix:
|
|
225
|
+
# previously returned None, so the --full installer would refuse
|
|
226
|
+
# to install ollama at all.
|
|
227
|
+
return ["bash", "-c", "curl -fsSL https://ollama.com/install.sh | sh"]
|
|
222
228
|
return None
|
|
223
229
|
|
|
224
230
|
|
|
@@ -36,6 +36,12 @@ Subcommands
|
|
|
36
36
|
telegram-chat-id <manifest> <omega_home>
|
|
37
37
|
Read ``telegram.group_chat_id`` from the manifest (if set) and
|
|
38
38
|
persist it through the vault. Returns the resolved id on stdout.
|
|
39
|
+
|
|
40
|
+
providers-from-catalog <omega_home>
|
|
41
|
+
--full mode fallback. Discover available providers from
|
|
42
|
+
Agentik_SSOT/llm-providers/providers-catalog.yaml — include any
|
|
43
|
+
whose first env var is set in the environment OR whose secret
|
|
44
|
+
already exists in the vault. Writes a default router.yaml.
|
|
39
45
|
"""
|
|
40
46
|
from __future__ import annotations
|
|
41
47
|
|
|
@@ -100,6 +106,108 @@ def cmd_providers(manifest: str, omega_home: str) -> int:
|
|
|
100
106
|
return 0
|
|
101
107
|
|
|
102
108
|
|
|
109
|
+
def _roles_for_cli(cli: str) -> list[str]:
|
|
110
|
+
"""Map an LLM CLI to default ModelRouter roles.
|
|
111
|
+
|
|
112
|
+
Reasoning:
|
|
113
|
+
* claude_code = Anthropic Claude — the canonical executor/dispatcher.
|
|
114
|
+
* gemini_cli = Google Gemini — strong general executor.
|
|
115
|
+
* codex = OpenAI Codex — executor (paid OpenAI API).
|
|
116
|
+
* opencode = multi-provider community CLI — anything goes.
|
|
117
|
+
* Others fall back to a generic "executor" role.
|
|
118
|
+
"""
|
|
119
|
+
cli = (cli or "").strip()
|
|
120
|
+
if cli == "claude_code":
|
|
121
|
+
return ["executor", "dispatcher"]
|
|
122
|
+
if cli == "opencode":
|
|
123
|
+
return ["executor", "worker"]
|
|
124
|
+
return ["executor"]
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def cmd_providers_from_catalog(omega_home: str) -> int:
|
|
128
|
+
"""--full mode fallback: auto-generate router.yaml from the catalog.
|
|
129
|
+
|
|
130
|
+
For every provider in
|
|
131
|
+
``Agentik_SSOT/llm-providers/providers-catalog.yaml`` whose first
|
|
132
|
+
secret_ref env var is present (in the live env or in the vault),
|
|
133
|
+
write a corresponding entry to ``Agentik_SSOT/providers/router.yaml``.
|
|
134
|
+
Providers with ``secret_refs: []`` (oauth / local) are always
|
|
135
|
+
eligible because they don't need an api key.
|
|
136
|
+
"""
|
|
137
|
+
home = Path(omega_home)
|
|
138
|
+
catalog_path = home / "Agentik_SSOT" / "llm-providers" / "providers-catalog.yaml"
|
|
139
|
+
if not catalog_path.exists():
|
|
140
|
+
print(f"no providers catalog at {catalog_path} — skipping")
|
|
141
|
+
return 0
|
|
142
|
+
try:
|
|
143
|
+
catalog = yaml.safe_load(catalog_path.read_text()) or {}
|
|
144
|
+
except yaml.YAMLError as exc:
|
|
145
|
+
print(f"catalog YAML error: {exc}")
|
|
146
|
+
return 0
|
|
147
|
+
entries = catalog.get("providers") or []
|
|
148
|
+
if not entries:
|
|
149
|
+
print(f"catalog at {catalog_path} has no `providers:` block")
|
|
150
|
+
return 0
|
|
151
|
+
|
|
152
|
+
# Vault is best-effort — if the engine isn't importable yet we just
|
|
153
|
+
# rely on os.environ.
|
|
154
|
+
_engine_on_path(home)
|
|
155
|
+
vault_read = None
|
|
156
|
+
try:
|
|
157
|
+
from omega_engine.vault import vault_read as _vr # type: ignore
|
|
158
|
+
vault_read = _vr
|
|
159
|
+
except Exception:
|
|
160
|
+
vault_read = None
|
|
161
|
+
|
|
162
|
+
def _has_secret(env_name: str) -> bool:
|
|
163
|
+
if os.environ.get(env_name):
|
|
164
|
+
return True
|
|
165
|
+
if vault_read is None:
|
|
166
|
+
return False
|
|
167
|
+
try:
|
|
168
|
+
v = vault_read(home, env_name)
|
|
169
|
+
return bool(v and v.strip())
|
|
170
|
+
except Exception:
|
|
171
|
+
return False
|
|
172
|
+
|
|
173
|
+
router: dict = {"providers": []}
|
|
174
|
+
discovered: list[str] = []
|
|
175
|
+
for entry in entries:
|
|
176
|
+
if not isinstance(entry, dict):
|
|
177
|
+
continue
|
|
178
|
+
pid = (entry.get("id") or "").strip()
|
|
179
|
+
if not pid:
|
|
180
|
+
continue
|
|
181
|
+
cli = (entry.get("cli") or "").strip()
|
|
182
|
+
refs = entry.get("secret_refs") or []
|
|
183
|
+
# Providers with no secret_refs at all (oauth / local — ollama,
|
|
184
|
+
# lm_studio, github_copilot, chatgpt_subscription) are eligible
|
|
185
|
+
# without a key check.
|
|
186
|
+
primary = refs[0] if refs else None
|
|
187
|
+
eligible = (primary is None) or _has_secret(primary)
|
|
188
|
+
if not eligible:
|
|
189
|
+
continue
|
|
190
|
+
router["providers"].append({
|
|
191
|
+
"id": pid,
|
|
192
|
+
"roles": _roles_for_cli(cli),
|
|
193
|
+
"enabled": True,
|
|
194
|
+
"secret_ref": primary or "",
|
|
195
|
+
"cli": cli,
|
|
196
|
+
})
|
|
197
|
+
discovered.append(pid)
|
|
198
|
+
|
|
199
|
+
out_dir = home / "Agentik_SSOT" / "providers"
|
|
200
|
+
out_dir.mkdir(parents=True, exist_ok=True)
|
|
201
|
+
target = out_dir / "router.yaml"
|
|
202
|
+
target.write_text(yaml.safe_dump(router, sort_keys=False, default_flow_style=False))
|
|
203
|
+
if discovered:
|
|
204
|
+
print(f"discovered providers from catalog: {discovered}")
|
|
205
|
+
else:
|
|
206
|
+
print("no providers discovered (no env vars / vault secrets set yet)")
|
|
207
|
+
print(f"wrote {target}")
|
|
208
|
+
return 0
|
|
209
|
+
|
|
210
|
+
|
|
103
211
|
def cmd_autonomous(manifest: str, templates_dir: str, target_dir: str) -> int:
|
|
104
212
|
data = _load_manifest(manifest)
|
|
105
213
|
agents = data.get("autonomous_agents") or []
|
|
@@ -362,6 +470,8 @@ def main(argv: list[str]) -> int:
|
|
|
362
470
|
rest = argv[2:]
|
|
363
471
|
if cmd == "providers" and len(rest) == 2:
|
|
364
472
|
return cmd_providers(*rest)
|
|
473
|
+
if cmd == "providers-from-catalog" and len(rest) == 1:
|
|
474
|
+
return cmd_providers_from_catalog(*rest)
|
|
365
475
|
if cmd == "autonomous" and len(rest) == 3:
|
|
366
476
|
return cmd_autonomous(*rest)
|
|
367
477
|
if cmd == "rag" and len(rest) == 2:
|
package/bootstrap/lib/steps.sh
CHANGED
|
@@ -14,7 +14,7 @@ step_preflight() {
|
|
|
14
14
|
return 1
|
|
15
15
|
fi
|
|
16
16
|
have git || { err "git is required"; return 1; }
|
|
17
|
-
[ "$OMEGA_PKG" = "unknown" ] && { err "no supported package manager (apt/dnf/brew)"; return 1; }
|
|
17
|
+
[ "$OMEGA_PKG" = "unknown" ] && { err "no supported package manager (apt/dnf/brew/pacman/apk/zypper)"; return 1; }
|
|
18
18
|
mkdir -p "$STATE_DIR/logs"
|
|
19
19
|
return 0
|
|
20
20
|
}
|
|
@@ -26,15 +26,64 @@ step_system_deps() {
|
|
|
26
26
|
# - fzf — primary picker for the new session manager (`omega`)
|
|
27
27
|
# and required by the tmux-claude install script too
|
|
28
28
|
# whiptail lives in `whiptail` (Debian/Ubuntu), `newt` (RHEL/Fedora),
|
|
29
|
-
# `newt` (Homebrew). fzf is `fzf`
|
|
29
|
+
# `libnewt` (Arch), `newt` (Alpine/SUSE), `newt` (Homebrew). fzf is `fzf`
|
|
30
|
+
# on every platform. nodejs+npm are required because 7 of 13 LLM CLIs
|
|
31
|
+
# (claude_code, gemini_cli, codex, opencode, qwen_code, continue_dev,
|
|
32
|
+
# gh_copilot) install via `npm -g`. Without npm at this step the LLM
|
|
33
|
+
# CLI installer (step 15) silently skips every Node-based CLI.
|
|
30
34
|
local pkgs="python3 git tmux sqlite3 jq curl"
|
|
31
35
|
case "$OMEGA_PKG" in
|
|
32
|
-
apt)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
apt) sudo apt-get update -qq \
|
|
37
|
+
&& sudo apt-get install -y -qq $pkgs whiptail fzf python3-venv python3-yaml nodejs npm ;;
|
|
38
|
+
dnf) sudo dnf install -y -q $pkgs newt fzf python3-pyyaml nodejs npm ;;
|
|
39
|
+
brew) brew install $pkgs newt fzf node 2>/dev/null || true ;;
|
|
40
|
+
pacman) sudo pacman -S --noconfirm --needed $pkgs libnewt fzf python-yaml nodejs npm ;;
|
|
41
|
+
apk) sudo apk add --no-cache $pkgs newt fzf py3-yaml nodejs npm ;;
|
|
42
|
+
zypper) sudo zypper --non-interactive install -y $pkgs newt fzf python3-PyYAML nodejs npm ;;
|
|
43
|
+
*) err "install manually: $pkgs (and whiptail/newt + fzf + nodejs/npm for the menu and LLM CLIs)"; return 1 ;;
|
|
36
44
|
esac
|
|
37
45
|
|
|
46
|
+
# npm version check — 7 of 13 LLM CLIs (claude_code, gemini_cli, codex,
|
|
47
|
+
# opencode, qwen_code, continue_dev, gh_copilot) require npm >= 9 for
|
|
48
|
+
# the agentic CLI install to be reliable. Older npm still works for
|
|
49
|
+
# plain installs; we warn but never fail.
|
|
50
|
+
if have npm; then
|
|
51
|
+
local _npm_v _npm_major
|
|
52
|
+
_npm_v="$(npm --version 2>/dev/null || echo 0)"
|
|
53
|
+
_npm_major="$(printf '%s' "$_npm_v" | cut -d. -f1)"
|
|
54
|
+
case "$_npm_major" in
|
|
55
|
+
''|*[!0-9]*) _npm_major=0 ;;
|
|
56
|
+
esac
|
|
57
|
+
if [ "$_npm_major" -lt 9 ]; then
|
|
58
|
+
info "warn: npm $_npm_v detected — LLM CLI install (step 15) recommends npm >= 9"
|
|
59
|
+
info " upgrade: npm install -g npm@latest (or use your OS package manager)"
|
|
60
|
+
fi
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
# tmux version check — the bundled pro config uses allow-passthrough,
|
|
64
|
+
# buffer-limit, and the modern hook syntax which require tmux >= 3.3.
|
|
65
|
+
# Older tmux still works (omega itself only needs basic features), but
|
|
66
|
+
# the pro profile emits errors on those config lines at load time.
|
|
67
|
+
if have tmux; then
|
|
68
|
+
local _tmux_v _tmux_major _tmux_minor
|
|
69
|
+
_tmux_v="$(tmux -V 2>/dev/null | awk '{print $2}' | tr -d -c '0-9.')"
|
|
70
|
+
if [ -n "$_tmux_v" ]; then
|
|
71
|
+
_tmux_major="$(printf '%s' "$_tmux_v" | cut -d. -f1)"
|
|
72
|
+
_tmux_minor="$(printf '%s' "$_tmux_v" | cut -d. -f2 | tr -d -c '0-9')"
|
|
73
|
+
case "$_tmux_major" in
|
|
74
|
+
''|*[!0-9]*) _tmux_major=0 ;;
|
|
75
|
+
esac
|
|
76
|
+
case "$_tmux_minor" in
|
|
77
|
+
''|*[!0-9]*) _tmux_minor=0 ;;
|
|
78
|
+
esac
|
|
79
|
+
if [ "$_tmux_major" -lt 3 ] || { [ "$_tmux_major" = "3" ] && [ "$_tmux_minor" -lt 3 ]; }; then
|
|
80
|
+
info "warn: tmux $_tmux_v detected — pro config requires >= 3.3"
|
|
81
|
+
info " some bindings (allow-passthrough, buffer-limit) may error at load"
|
|
82
|
+
info " upgrade via your OS package manager ($OMEGA_PKG) and reinstall tmux"
|
|
83
|
+
fi
|
|
84
|
+
fi
|
|
85
|
+
fi
|
|
86
|
+
|
|
38
87
|
# PyYAML — required by every install-side helper that reads the manifest
|
|
39
88
|
# or audit YAMLs (bootstrap/lib/llm-clis.py, manifest-helpers.py, audit
|
|
40
89
|
# generator). apt/dnf already deliver it via the system package above.
|
|
@@ -134,9 +183,12 @@ step_system_deps() {
|
|
|
134
183
|
if ! have age; then
|
|
135
184
|
info "installing age (powers the encrypted secrets vault)"
|
|
136
185
|
case "$OMEGA_PKG" in
|
|
137
|
-
apt)
|
|
138
|
-
dnf)
|
|
139
|
-
brew)
|
|
186
|
+
apt) sudo apt-get install -y -qq age 2>>"$LOG_FILE" || info "age install failed (non-fatal)" ;;
|
|
187
|
+
dnf) sudo dnf install -y -q age 2>>"$LOG_FILE" || info "age install failed (non-fatal)" ;;
|
|
188
|
+
brew) brew install age 2>>"$LOG_FILE" || info "age install failed (non-fatal)" ;;
|
|
189
|
+
pacman) sudo pacman -S --noconfirm --needed age 2>>"$LOG_FILE" || info "age install failed (non-fatal)" ;;
|
|
190
|
+
apk) sudo apk add --no-cache age 2>>"$LOG_FILE" || info "age install failed (non-fatal)" ;;
|
|
191
|
+
zypper) sudo zypper --non-interactive install -y age 2>>"$LOG_FILE" || info "age install failed (non-fatal)" ;;
|
|
140
192
|
esac
|
|
141
193
|
fi
|
|
142
194
|
if ! have uv && [ ! -x "$HOME/.local/bin/uv" ]; then
|
|
@@ -204,7 +256,13 @@ step_llm_clis() {
|
|
|
204
256
|
python3 "$helper" install "$MANIFEST" | sed 's/^/ /'
|
|
205
257
|
return 0
|
|
206
258
|
fi
|
|
207
|
-
|
|
259
|
+
# v0.19.43 — --full mode (NONINTERACTIVE=1 + no MANIFEST) used to skip
|
|
260
|
+
# silently, leaving the operator with zero LLM CLIs after `npx ... --full`.
|
|
261
|
+
# Install the recommended set instead. install_cli is idempotent (skips
|
|
262
|
+
# already-installed CLIs), so this is safe on every entry.
|
|
263
|
+
info "headless --full mode: installing recommended LLM CLI set (claude_code + gemini_cli + opencode)"
|
|
264
|
+
python3 "$helper" install claude_code gemini_cli opencode | sed 's/^/ /' || \
|
|
265
|
+
warn "recommended LLM CLI install returned non-zero (non-fatal)"
|
|
208
266
|
return 0
|
|
209
267
|
fi
|
|
210
268
|
|
|
@@ -351,7 +409,16 @@ step_engine() {
|
|
|
351
409
|
local uv_bin; uv_bin="$(command -v uv || echo "$HOME/.local/bin/uv")"
|
|
352
410
|
[ -x "$uv_bin" ] || { err "uv not found after step 10"; return 1; }
|
|
353
411
|
cd "$OMEGA_HOME/Agentik_Engine" || { err "engine block missing"; return 1; }
|
|
354
|
-
|
|
412
|
+
# Pin engine venv to Python 3.13 — uv will download an Astral-managed
|
|
413
|
+
# build if the host's python3 is broken or unavailable. This sidesteps
|
|
414
|
+
# the macOS Tahoe brew Python 3.14 libexpat ABI mismatch and any other
|
|
415
|
+
# "system python3 silently inherited" failure mode. Fall back to a
|
|
416
|
+
# bare `uv venv` (uses whatever python3 is on PATH) so the install
|
|
417
|
+
# still succeeds on hosts where Python 3.13 cannot be procured.
|
|
418
|
+
if ! "$uv_bin" venv --python 3.13 >/dev/null 2>&1; then
|
|
419
|
+
info "engine venv: uv venv --python 3.13 failed, falling back to system python3"
|
|
420
|
+
"$uv_bin" venv >/dev/null 2>&1 || { err "uv venv failed"; return 1; }
|
|
421
|
+
fi
|
|
355
422
|
"$uv_bin" pip install -e . >/dev/null 2>&1 || { err "engine install failed"; return 1; }
|
|
356
423
|
mkdir -p "$OMEGA_HOME/Agentik_Tools/bin"
|
|
357
424
|
ln -sf "$OMEGA_HOME/Agentik_Engine/.venv/bin/omega" "$OMEGA_HOME/Agentik_Tools/bin/omega"
|
|
@@ -387,9 +454,16 @@ step_tmux_config() {
|
|
|
387
454
|
fi
|
|
388
455
|
local marker="$HOME/.tmux/scripts/session-manager.sh"
|
|
389
456
|
local installer_url="https://raw.githubusercontent.com/agentik-os/tmux-claude/main/install.sh"
|
|
457
|
+
# v0.19.43 — track whether ~/.tmux.conf is a tmux-claude install (either
|
|
458
|
+
# already present OR freshly installed by the curl pipe). When it is, we
|
|
459
|
+
# MUST also wire the Omega add-on (Alt+O bind) via
|
|
460
|
+
# install_into_home_tmux_conf — otherwise the user has tmux-claude but
|
|
461
|
+
# no way to reach the Omega menu from tmux.
|
|
462
|
+
local upstream_present=0
|
|
390
463
|
|
|
391
464
|
if [ -f "$marker" ]; then
|
|
392
|
-
info "tmux-claude already installed at $marker — skipping"
|
|
465
|
+
info "tmux-claude already installed at $marker — skipping curl"
|
|
466
|
+
upstream_present=1
|
|
393
467
|
elif have curl; then
|
|
394
468
|
info "installing canonical tmux-claude setup (agentik-os/tmux-claude)…"
|
|
395
469
|
# We pipe through `bash -s -- --no-prompt` so the install doesn't ask
|
|
@@ -398,6 +472,7 @@ step_tmux_config() {
|
|
|
398
472
|
if curl -fsSL "$installer_url" 2>>"$LOG_FILE" \
|
|
399
473
|
| bash -s -- --no-prompt >>"$LOG_FILE" 2>&1; then
|
|
400
474
|
ok "tmux-claude installed (~/.tmux/scripts/, ~/.tmux.conf)"
|
|
475
|
+
upstream_present=1
|
|
401
476
|
else
|
|
402
477
|
err "tmux-claude install failed — falling back to bundled pro profile"
|
|
403
478
|
_tmux_fallback_pro_config
|
|
@@ -407,6 +482,28 @@ step_tmux_config() {
|
|
|
407
482
|
_tmux_fallback_pro_config
|
|
408
483
|
fi
|
|
409
484
|
|
|
485
|
+
# v0.19.43 — wire the Omega add-on AFTER an upstream tmux-claude install
|
|
486
|
+
# succeeds (or was already present). Without this step the upstream
|
|
487
|
+
# ~/.tmux.conf has NO `source-file` line for the OmegaOS add-on, so the
|
|
488
|
+
# Alt+O / Ctrl-b o binds never get sourced. install_into_home_tmux_conf
|
|
489
|
+
# detects the tmux-claude markers and falls into the
|
|
490
|
+
# preserved-tmux-claude branch — drops omega-tmux-add.conf and appends
|
|
491
|
+
# the source-file line at the end of ~/.tmux.conf.
|
|
492
|
+
# The fallback path already wires the add-on via _tmux_fallback_pro_config
|
|
493
|
+
# → install_into_home_tmux_conf, so we only need to do it here for the
|
|
494
|
+
# happy path.
|
|
495
|
+
if [ "$upstream_present" = "1" ]; then
|
|
496
|
+
PYTHONPATH="$OMEGA_HOME/Agentik_Engine" python3 - <<PY 2>>"$LOG_FILE" || warn "Omega tmux add-on wire failed (non-fatal)"
|
|
497
|
+
import os
|
|
498
|
+
os.environ["OMEGA_HOME"] = "$OMEGA_HOME"
|
|
499
|
+
from omega_engine.tmux import install_into_home_tmux_conf
|
|
500
|
+
result = install_into_home_tmux_conf(profile="pro")
|
|
501
|
+
print(f" Omega tmux wired: mode={result['mode']}")
|
|
502
|
+
print(f" written: {result['written']}")
|
|
503
|
+
print(f" bundled copy: {result['bundled_copy']}")
|
|
504
|
+
PY
|
|
505
|
+
fi
|
|
506
|
+
|
|
410
507
|
# Always also drop the bundled config under $OMEGA_HOME so `omega tmux
|
|
411
508
|
# install --profile pro` later remains a working manual recovery path.
|
|
412
509
|
PYTHONPATH="$OMEGA_HOME/Agentik_Engine" python3 - <<PY 2>>"$LOG_FILE"
|
|
@@ -585,6 +682,15 @@ for entry in missing:
|
|
|
585
682
|
elif pkg == "dnf":
|
|
586
683
|
rc, out = _run(["sudo", "dnf", "install", "-y", "-q", install[pkg]])
|
|
587
684
|
attempt = f"dnf install {install[pkg]}"
|
|
685
|
+
elif pkg == "pacman":
|
|
686
|
+
rc, out = _run(["sudo", "pacman", "-S", "--noconfirm", "--needed", install[pkg]])
|
|
687
|
+
attempt = f"pacman -S {install[pkg]}"
|
|
688
|
+
elif pkg == "apk":
|
|
689
|
+
rc, out = _run(["sudo", "apk", "add", "--no-cache", install[pkg]])
|
|
690
|
+
attempt = f"apk add {install[pkg]}"
|
|
691
|
+
elif pkg == "zypper":
|
|
692
|
+
rc, out = _run(["sudo", "zypper", "--non-interactive", "install", "-y", install[pkg]])
|
|
693
|
+
attempt = f"zypper install {install[pkg]}"
|
|
588
694
|
elif "npm_global" in install and shutil.which("npm"):
|
|
589
695
|
rc, out = _run(["npm", "install", "-g", "--silent", install["npm_global"]])
|
|
590
696
|
attempt = f"npm install -g {install['npm_global']}"
|
|
@@ -1107,6 +1213,32 @@ _claude_plugins_prompt_checklist() {
|
|
|
1107
1213
|
fi
|
|
1108
1214
|
}
|
|
1109
1215
|
|
|
1216
|
+
# --- 47 -----------------------------------------------------------------------
|
|
1217
|
+
#
|
|
1218
|
+
# step_paperclip — register OmegaOS as the "omegaos" company with Paperclip.
|
|
1219
|
+
#
|
|
1220
|
+
# v0.19.43 — auto-runs at install time so the user doesn't have to type
|
|
1221
|
+
# `omega paperclip register` manually. Idempotent: if the 14 agents are
|
|
1222
|
+
# already registered, re-runs are a no-op content-equality check.
|
|
1223
|
+
#
|
|
1224
|
+
# This step does NOT install the Paperclip dashboard binary itself — that
|
|
1225
|
+
# remains opt-in via `omega tool install paperclipai`. It only writes the
|
|
1226
|
+
# company.json + per-agent JSON files at ~/.paperclip/companies/omegaos/
|
|
1227
|
+
# so Paperclip can SEE OmegaOS as soon as the operator starts the daemon.
|
|
1228
|
+
step_paperclip() {
|
|
1229
|
+
PYTHONPATH="$OMEGA_HOME/Agentik_Engine" python3 - <<PY 2>>"$LOG_FILE"
|
|
1230
|
+
import os
|
|
1231
|
+
os.environ["OMEGA_HOME"] = "$OMEGA_HOME"
|
|
1232
|
+
from omega_engine import paperclip_bridge as PB
|
|
1233
|
+
result = PB.register()
|
|
1234
|
+
print(f" Paperclip company registered: omegaos")
|
|
1235
|
+
print(f" agents written: {result.get('agents_written', 0)}")
|
|
1236
|
+
print(f" workspaces written: {result.get('workspaces_written', 0)}")
|
|
1237
|
+
print(f" paperclip_home: {result.get('paperclip_home', '?')}")
|
|
1238
|
+
PY
|
|
1239
|
+
return $?
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1110
1242
|
# --- 50 -----------------------------------------------------------------------
|
|
1111
1243
|
step_telegram() {
|
|
1112
1244
|
# Two distinct bots in the corrected v0.19.14 model:
|
|
@@ -1268,7 +1400,14 @@ step_accounts() {
|
|
|
1268
1400
|
# we skip and the operator wires providers later via env or `omega account`.
|
|
1269
1401
|
step_providers() {
|
|
1270
1402
|
if [ -z "${MANIFEST:-}" ] || [ ! -f "$MANIFEST" ]; then
|
|
1271
|
-
|
|
1403
|
+
# v0.19.43 — used to skip silently, leaving the runtime ModelRouter
|
|
1404
|
+
# with no router.yaml. Now auto-generate one from the live providers
|
|
1405
|
+
# catalog: any provider whose primary env var is set OR whose vault
|
|
1406
|
+
# secret exists is included. Oauth/local providers are always
|
|
1407
|
+
# included (no key needed).
|
|
1408
|
+
info "no manifest providers — auto-discovering from catalog"
|
|
1409
|
+
python3 "$OMEGA_REPO/bootstrap/lib/manifest-helpers.py" providers-from-catalog "$OMEGA_HOME" \
|
|
1410
|
+
| sed 's/^/ /'
|
|
1272
1411
|
return 0
|
|
1273
1412
|
fi
|
|
1274
1413
|
python3 "$OMEGA_REPO/bootstrap/lib/manifest-helpers.py" providers "$MANIFEST" "$OMEGA_HOME" \
|
|
@@ -1337,17 +1476,22 @@ step_first_project() {
|
|
|
1337
1476
|
|
|
1338
1477
|
# --- 59 -----------------------------------------------------------------------
|
|
1339
1478
|
#
|
|
1340
|
-
#
|
|
1479
|
+
# step_aisb_session — guarantee one always-on AISB master chat window.
|
|
1480
|
+
#
|
|
1481
|
+
# v0.19.43 — RENAMED from step_hermes_session (which was a misnomer: it
|
|
1482
|
+
# spawned the AISB master chat, not Hermès). v0.19.43 also moved the
|
|
1483
|
+
# chat from a standalone tmux session to a WINDOW inside the Omega
|
|
1484
|
+
# master session (Omega:aisb). spawn_aisb_chat now returns "Omega:aisb"
|
|
1485
|
+
# and spawns the Omega master if needed.
|
|
1341
1486
|
#
|
|
1342
|
-
#
|
|
1343
|
-
#
|
|
1344
|
-
#
|
|
1345
|
-
#
|
|
1346
|
-
# not need internet).
|
|
1487
|
+
# This is the operator's terminal-side conversation entry point —
|
|
1488
|
+
# critical when Telegram isn't wired (minimal profile, or chat_id not
|
|
1489
|
+
# yet set), and still useful when it IS wired (an always-attached local
|
|
1490
|
+
# fallback that does not need internet).
|
|
1347
1491
|
#
|
|
1348
|
-
# Idempotent: if
|
|
1492
|
+
# Idempotent: if the aisb window already exists, we just print attach
|
|
1349
1493
|
# instructions.
|
|
1350
|
-
|
|
1494
|
+
step_aisb_session() {
|
|
1351
1495
|
if ! have tmux; then
|
|
1352
1496
|
err "tmux not installed — step_system_deps should have caught this"
|
|
1353
1497
|
return 1
|
|
@@ -1359,13 +1503,16 @@ step_hermes_session() {
|
|
|
1359
1503
|
import os
|
|
1360
1504
|
os.environ["OMEGA_HOME"] = "$OMEGA_HOME"
|
|
1361
1505
|
from omega_engine import tmux
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1506
|
+
# v0.19.43 — AISB master chat is now a WINDOW under the Omega master
|
|
1507
|
+
# session. omega_window_alive() checks the aisb window specifically;
|
|
1508
|
+
# attach_command() returns the right `tmux attach -t Omega:aisb` form.
|
|
1509
|
+
target = "Omega:aisb"
|
|
1510
|
+
if tmux.omega_window_alive("aisb"):
|
|
1511
|
+
print(f" AISB chat window already running: {target}")
|
|
1365
1512
|
else:
|
|
1366
1513
|
tmux.spawn_aisb_chat("$OMEGA_HOME")
|
|
1367
|
-
print(f" spawned: {
|
|
1368
|
-
print(f" attach: {tmux.attach_command(
|
|
1514
|
+
print(f" spawned: {target} (always-on AISB master conversation)")
|
|
1515
|
+
print(f" attach: {tmux.attach_command(target)}")
|
|
1369
1516
|
print(f" detach: Ctrl-b d (session keeps running)")
|
|
1370
1517
|
PY
|
|
1371
1518
|
return $?
|
|
@@ -1373,6 +1520,63 @@ PY
|
|
|
1373
1520
|
|
|
1374
1521
|
# --- 60 -----------------------------------------------------------------------
|
|
1375
1522
|
#
|
|
1523
|
+
# step_hermes_session — spawn the always-on Hermès chat window, IF the
|
|
1524
|
+
# vault key is present.
|
|
1525
|
+
#
|
|
1526
|
+
# v0.19.43 — separate step from step_aisb_session (which was previously
|
|
1527
|
+
# misnamed step_hermes_session but spawned AISB). Hermès has its own
|
|
1528
|
+
# credential isolation contract (ANTHROPIC_API_KEY_HERMES from the
|
|
1529
|
+
# vault — see omega_engine/hermes.py for the resolution chain). If the
|
|
1530
|
+
# vault key is missing we SKIP this step instead of falling back to Max
|
|
1531
|
+
# OAuth — operators who want Hermès running 24/7 must wire the key
|
|
1532
|
+
# explicitly. (Interactive `omega hermes` still falls through to Max
|
|
1533
|
+
# OAuth as a last resort so users can experiment without a paid key.)
|
|
1534
|
+
step_hermes_session() {
|
|
1535
|
+
if ! have tmux; then
|
|
1536
|
+
err "tmux not installed — step_system_deps should have caught this"
|
|
1537
|
+
return 1
|
|
1538
|
+
fi
|
|
1539
|
+
local omega="$OMEGA_HOME/Agentik_Tools/bin/omega"
|
|
1540
|
+
[ -x "$omega" ] || { err "omega CLI not found at $omega — step_engine incomplete"; return 1; }
|
|
1541
|
+
|
|
1542
|
+
local key_present=0
|
|
1543
|
+
if PYTHONPATH="$OMEGA_HOME/Agentik_Engine" python3 - <<PY 2>/dev/null
|
|
1544
|
+
from pathlib import Path
|
|
1545
|
+
import os, sys
|
|
1546
|
+
home = Path(os.environ.get("OMEGA_HOME", str(Path.home() / "Omega")))
|
|
1547
|
+
try:
|
|
1548
|
+
from omega_engine.vault import vault_read
|
|
1549
|
+
k = vault_read(home, "ANTHROPIC_API_KEY_HERMES")
|
|
1550
|
+
sys.exit(0 if (k and k.strip()) else 1)
|
|
1551
|
+
except Exception:
|
|
1552
|
+
sys.exit(1)
|
|
1553
|
+
PY
|
|
1554
|
+
then
|
|
1555
|
+
key_present=1
|
|
1556
|
+
fi
|
|
1557
|
+
|
|
1558
|
+
if [ "$key_present" = "1" ]; then
|
|
1559
|
+
PYTHONPATH="$OMEGA_HOME/Agentik_Engine" python3 - <<PY 2>>"$LOG_FILE"
|
|
1560
|
+
import os
|
|
1561
|
+
os.environ["OMEGA_HOME"] = "$OMEGA_HOME"
|
|
1562
|
+
from omega_engine import tmux
|
|
1563
|
+
target = "Omega:hermes"
|
|
1564
|
+
if tmux.omega_window_alive("hermes"):
|
|
1565
|
+
print(f" Hermès chat window already running: {target}")
|
|
1566
|
+
else:
|
|
1567
|
+
tmux.spawn_hermes_chat("$OMEGA_HOME")
|
|
1568
|
+
print(f" spawned: {target} (always-on Hermès conversation)")
|
|
1569
|
+
print(f" attach: {tmux.attach_command(target)}")
|
|
1570
|
+
PY
|
|
1571
|
+
else
|
|
1572
|
+
info " Hermès vault key (ANTHROPIC_API_KEY_HERMES) absent — skipping persistent session"
|
|
1573
|
+
info " wire it with: omega vault write ANTHROPIC_API_KEY_HERMES sk-ant-..."
|
|
1574
|
+
fi
|
|
1575
|
+
return 0
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
# --- 65 -----------------------------------------------------------------------
|
|
1579
|
+
#
|
|
1376
1580
|
# step_services — install the 24/7 service layer.
|
|
1377
1581
|
#
|
|
1378
1582
|
# Linux: write 3 systemd user units, `daemon-reload`, then `enable --now`.
|
|
@@ -38,6 +38,15 @@ v7.0 adds R-XX ownership and updated tooling without renaming any agent.
|
|
|
38
38
|
|
|
39
39
|
## Architecture
|
|
40
40
|
|
|
41
|
+
> **L0 Paperclip governance.** OmegaOS is registered as the "omegaos"
|
|
42
|
+
> company at `~/.paperclip/companies/omegaos/` with 14 agents (Hermès +
|
|
43
|
+
> 13 AISB). Each agent has a fixed reporting line (Hermès → top; Niobe
|
|
44
|
+
> → Hermès; Oracle/Construct/Morpheus/Architect → Oracle's chain).
|
|
45
|
+
> Agents should call `paperclip_bridge.send_heartbeat()` at meaningful
|
|
46
|
+
> lifecycle events (spawn / mission complete / blocked) so the
|
|
47
|
+
> Paperclip dashboard surfaces live status to the operator. This is
|
|
48
|
+
> additive — no AISB agent depends on Paperclip being running.
|
|
49
|
+
|
|
41
50
|
```
|
|
42
51
|
USER (Telegram)
|
|
43
52
|
|
|
|
@@ -274,6 +283,10 @@ Handoff templates: `protocols/handoff-templates.md`
|
|
|
274
283
|
Shared protocol: `protocols/shared-protocol.md`
|
|
275
284
|
LMC (Lead-Manager-Checker) protocol: `protocols/lmc-protocol.md` for SERAPH-grade audits.
|
|
276
285
|
|
|
286
|
+
**Fresh context handoff** — every brief dispatched downstream MUST be self-contained:
|
|
287
|
+
Mission / Purpose / Context / Done Criteria / Verify Command. The receiving agent
|
|
288
|
+
never sees this conversation; if it isn't written into the brief, it does not exist.
|
|
289
|
+
|
|
277
290
|
---
|
|
278
291
|
|
|
279
292
|
## AISB Nerve (v2.0, Omega-aware)
|
package/install.sh
CHANGED
|
@@ -195,6 +195,7 @@ STEPS=(
|
|
|
195
195
|
# omega tool install <id> (still wired for one-offs)
|
|
196
196
|
"40-clis:step_clis"
|
|
197
197
|
"45-claude-plugins:step_claude_plugins"
|
|
198
|
+
"47-paperclip:step_paperclip"
|
|
198
199
|
)
|
|
199
200
|
if [ "$PROFILE" != "minimal" ]; then
|
|
200
201
|
# In --full mode the Telegram step is gated by the single yes/no asked
|
|
@@ -207,8 +208,13 @@ STEPS+=(
|
|
|
207
208
|
"55-autonomous:step_autonomous"
|
|
208
209
|
"57-rag:step_rag"
|
|
209
210
|
"58-first-project:step_first_project"
|
|
210
|
-
|
|
211
|
-
|
|
211
|
+
# v0.19.43 — 59-aisb-session (renamed from the misnamed 59-hermes-session)
|
|
212
|
+
# spawns the always-on AISB master chat window. 60-hermes-session is a
|
|
213
|
+
# NEW step that conditionally spawns the Hermès chat window when the
|
|
214
|
+
# ANTHROPIC_API_KEY_HERMES vault key is present (else skips cleanly).
|
|
215
|
+
"59-aisb-session:step_aisb_session"
|
|
216
|
+
"60-hermes-session:step_hermes_session"
|
|
217
|
+
"65-services:step_services"
|
|
212
218
|
"70-doctor:step_doctor"
|
|
213
219
|
)
|
|
214
220
|
export STEP_TOTAL="${#STEPS[@]}"
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|