@agentikos/omega-os 0.19.11 → 0.19.13
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 +44 -1
- package/bootstrap/lib/steps.sh +6 -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__/aisb_chat.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/cli.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/aisb_chat.py +43 -0
- package/omega/Agentik_Engine/omega_engine/cli.py +38 -9
- package/omega/Agentik_Engine/omega_engine/daemons/__pycache__/telegram.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/daemons/telegram.py +27 -14
- package/omega/Agentik_Engine/omega_engine/genesis/__pycache__/stack.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/genesis/stack.py +30 -0
- package/omega/Agentik_Engine/pyproject.toml +1 -1
- package/omega/Agentik_Engine/tests/__pycache__/test_install_steps.cpython-313-pytest-8.4.2.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_install_steps.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_telegram_history.cpython-313-pytest-8.4.2.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_telegram_history.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/tests/test_install_steps.py +4 -1
- package/omega/Agentik_Engine/tests/test_telegram_history.py +63 -15
- package/omega/Agentik_SSOT/VERSION +1 -1
- package/omega/Agentik_SSOT/docs/references/README.md +17 -0
- package/omega/Agentik_SSOT/skills/desktop-architecture/SKILL.md +61 -0
- package/package.json +1 -1
package/bootstrap/lib/common.sh
CHANGED
|
@@ -232,6 +232,38 @@ ask() {
|
|
|
232
232
|
# UX — banner, preflight card, profile picker, step progress, post-install
|
|
233
233
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
234
234
|
|
|
235
|
+
# NEWT_COLORS — whiptail palette in Claude theme. Without this, whiptail
|
|
236
|
+
# defaults to the loud blue Windows-95 look. NEWT only knows 16 named
|
|
237
|
+
# colors, so we map the Claude warm-light theme to the closest pairs:
|
|
238
|
+
# brown ≈ #D97757 (Claude orange — used for accents)
|
|
239
|
+
# lightgray ≈ off-white body text
|
|
240
|
+
# black = backdrop (matches dark terminals)
|
|
241
|
+
# This is exported into install.sh's env AND wired into the user's
|
|
242
|
+
# shellrc by path_setup_user_rc so `omega` (the menu) also picks it up.
|
|
243
|
+
export NEWT_COLORS='
|
|
244
|
+
root=lightgray,black
|
|
245
|
+
window=lightgray,black
|
|
246
|
+
shadow=black,black
|
|
247
|
+
title=brown,black
|
|
248
|
+
border=brown,black
|
|
249
|
+
textbox=lightgray,black
|
|
250
|
+
listbox=lightgray,black
|
|
251
|
+
sellistbox=black,brown
|
|
252
|
+
actsellistbox=white,brown
|
|
253
|
+
button=black,brown
|
|
254
|
+
actbutton=white,brown
|
|
255
|
+
compactbutton=brown,black
|
|
256
|
+
checkbox=brown,black
|
|
257
|
+
actcheckbox=white,brown
|
|
258
|
+
entry=lightgray,black
|
|
259
|
+
disentry=gray,black
|
|
260
|
+
label=brown,black
|
|
261
|
+
helpline=brown,black
|
|
262
|
+
roottext=brown,black
|
|
263
|
+
emptyscale=black,gray
|
|
264
|
+
fullscale=brown,brown
|
|
265
|
+
'
|
|
266
|
+
|
|
235
267
|
if [ -t 1 ]; then
|
|
236
268
|
C_BOLD=$'\033[1m'
|
|
237
269
|
# Claude Code light theme — derived from tweakcn.com/r/themes/claude.json.
|
|
@@ -447,12 +479,17 @@ path_setup_user_rc() {
|
|
|
447
479
|
return 0
|
|
448
480
|
fi
|
|
449
481
|
mkdir -p "$(dirname "$rc")"
|
|
482
|
+
# Build the NEWT_COLORS one-liner so the user's interactive `omega`
|
|
483
|
+
# menu uses the Claude theme too (orange accents, no Win-95 blue).
|
|
484
|
+
local newt_oneline
|
|
485
|
+
newt_oneline="$(printf '%s' "$NEWT_COLORS" | tr '\n' ':' | sed 's/^://;s/:$//')"
|
|
450
486
|
if [ "$(basename "$rc")" = "config.fish" ]; then
|
|
451
487
|
{
|
|
452
488
|
echo ""
|
|
453
489
|
echo "$marker"
|
|
454
490
|
echo "set -gx OMEGA_HOME \"$OMEGA_HOME\""
|
|
455
491
|
echo "set -gx PATH \"\$OMEGA_HOME/Agentik_Tools/bin\" \$PATH"
|
|
492
|
+
echo "set -gx NEWT_COLORS '$newt_oneline'"
|
|
456
493
|
echo "$close"
|
|
457
494
|
} >> "$rc"
|
|
458
495
|
else
|
|
@@ -461,6 +498,7 @@ path_setup_user_rc() {
|
|
|
461
498
|
echo "$marker"
|
|
462
499
|
echo "export OMEGA_HOME=\"$OMEGA_HOME\""
|
|
463
500
|
echo "export PATH=\"\$OMEGA_HOME/Agentik_Tools/bin:\$PATH\""
|
|
501
|
+
echo "export NEWT_COLORS='$newt_oneline'"
|
|
464
502
|
echo "$close"
|
|
465
503
|
} >> "$rc"
|
|
466
504
|
fi
|
|
@@ -478,7 +516,12 @@ post_install_card() {
|
|
|
478
516
|
| python3 -c 'import sys,json
|
|
479
517
|
try: d=json.load(sys.stdin); print(d.get("readiness","unknown"))
|
|
480
518
|
except Exception: print("unknown")' 2>/dev/null)" || readiness="unknown"
|
|
481
|
-
|
|
519
|
+
# macOS ships Bash 3.2 (Apple won't update due to GPLv3) — no
|
|
520
|
+
# ${var,,} support. Use `tr` for the lowercase normalize so the
|
|
521
|
+
# installer works on Mac out of the box.
|
|
522
|
+
local readiness_lc
|
|
523
|
+
readiness_lc="$(printf '%s' "$readiness" | tr '[:upper:]' '[:lower:]')"
|
|
524
|
+
case "$readiness_lc" in
|
|
482
525
|
ready) verdict_text="READY" ; verdict_color="$C_GREEN" ;;
|
|
483
526
|
partial) verdict_text="PARTIAL" ; verdict_color="$C_YELLOW" ;;
|
|
484
527
|
not-ready|not_ready) verdict_text="NOT READY"; verdict_color="$C_RED" ;;
|
package/bootstrap/lib/steps.sh
CHANGED
|
@@ -448,7 +448,12 @@ PY
|
|
|
448
448
|
step_mcp() {
|
|
449
449
|
local catalog="$OMEGA_HOME/Agentik_SSOT/mcp/mcp-catalog.yaml"
|
|
450
450
|
[ -f "$catalog" ] || { err "MCP catalog missing: $catalog"; return 1; }
|
|
451
|
-
|
|
451
|
+
# grep -c exits 1 when count is 0, which made the old `|| echo '?'`
|
|
452
|
+
# fire AND grep's "0" stayed printed → "0\n? entries" splatter.
|
|
453
|
+
local _mcp_count
|
|
454
|
+
_mcp_count="$(grep -c '^- id:' "$catalog" 2>/dev/null || true)"
|
|
455
|
+
_mcp_count="$(printf '%s' "$_mcp_count" | tr -d '\n ' )"
|
|
456
|
+
info "MCP catalog present (${_mcp_count:-?} entries)"
|
|
452
457
|
|
|
453
458
|
# Collect the selection into newline-separated $selected.
|
|
454
459
|
local selected=""
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -60,6 +60,49 @@ def _clear_history(home: Path) -> int:
|
|
|
60
60
|
conn.close()
|
|
61
61
|
|
|
62
62
|
|
|
63
|
+
def chat_once(home: Path, text: str, *,
|
|
64
|
+
topic_id: int = None,
|
|
65
|
+
record_history: bool = True) -> str:
|
|
66
|
+
"""Run ONE conversation turn against the AISB envelope and return the
|
|
67
|
+
reply. Stateless from the caller's POV — history is persisted via
|
|
68
|
+
``telegram_history`` keyed on ``topic_id`` (a single global default
|
|
69
|
+
for the tmux REPL; chat_id for Telegram DMs to keep per-user threads).
|
|
70
|
+
|
|
71
|
+
Extracted so the Telegram DM path can talk to the same agent the
|
|
72
|
+
tmux REPL talks to, without duplicating env+envelope+provider plumbing.
|
|
73
|
+
"""
|
|
74
|
+
import time
|
|
75
|
+
from omega_engine.envelope import EnvelopeContext, build_envelope
|
|
76
|
+
from omega_engine.provider import AgentRequest
|
|
77
|
+
from omega_engine.router import ModelRouter
|
|
78
|
+
from omega_engine.telegram_history import (
|
|
79
|
+
build_context_prompt, record_inbound, record_outbound,
|
|
80
|
+
)
|
|
81
|
+
if topic_id is None:
|
|
82
|
+
topic_id = CHAT_TOPIC
|
|
83
|
+
if record_history:
|
|
84
|
+
record_inbound(home, topic_id=topic_id, text=text)
|
|
85
|
+
enriched = build_context_prompt(
|
|
86
|
+
home, topic_id=topic_id, new_intent=text, limit=10,
|
|
87
|
+
)
|
|
88
|
+
ctx = EnvelopeContext(
|
|
89
|
+
role="aisb",
|
|
90
|
+
intent=enriched,
|
|
91
|
+
task_id=f"chat-{int(time.time())}",
|
|
92
|
+
)
|
|
93
|
+
env = build_envelope(home, ctx)
|
|
94
|
+
router = ModelRouter.auto()
|
|
95
|
+
provider = router.resolve("aisb")
|
|
96
|
+
result = provider.run(AgentRequest(
|
|
97
|
+
role="aisb", prompt=env["user"], context={},
|
|
98
|
+
system=env["system"],
|
|
99
|
+
))
|
|
100
|
+
reply = (result.text or "").strip() or "(empty reply)"
|
|
101
|
+
if record_history:
|
|
102
|
+
record_outbound(home, topic_id=topic_id, text=reply)
|
|
103
|
+
return reply
|
|
104
|
+
|
|
105
|
+
|
|
63
106
|
def run_chat_loop() -> int:
|
|
64
107
|
"""Block until /quit. Returns 0 on clean exit."""
|
|
65
108
|
home = _omega_home()
|
|
@@ -275,14 +275,21 @@ def cmd_doctor(args: argparse.Namespace) -> int:
|
|
|
275
275
|
section("llm clis")
|
|
276
276
|
import shutil as _shu
|
|
277
277
|
import subprocess as _sup
|
|
278
|
-
|
|
278
|
+
# CLI specs split into REQUIRED (Claude Code is the only one we hard-
|
|
279
|
+
# require — everything else is genuinely optional). Optional CLIs that
|
|
280
|
+
# aren't installed are reported as ``info``, NOT ``warn``, so they no
|
|
281
|
+
# longer drag a clean install down to PARTIAL when the user opted out.
|
|
282
|
+
_required_clis = [
|
|
279
283
|
("claude_code", "claude", ["claude", "--version"]),
|
|
284
|
+
]
|
|
285
|
+
_optional_clis = [
|
|
280
286
|
("gemini_cli", "gemini", ["gemini", "--version"]),
|
|
281
287
|
("codex", "codex", ["codex", "--version"]),
|
|
282
288
|
("aider", "aider", ["aider", "--version"]),
|
|
283
289
|
]
|
|
284
290
|
any_cli = False
|
|
285
|
-
for cli_id, bin_name, ver_cmd in
|
|
291
|
+
for cli_id, bin_name, ver_cmd in _required_clis + _optional_clis:
|
|
292
|
+
is_optional = (cli_id, bin_name, ver_cmd) in _optional_clis
|
|
286
293
|
if _shu.which(bin_name):
|
|
287
294
|
any_cli = True
|
|
288
295
|
try:
|
|
@@ -293,16 +300,21 @@ def cmd_doctor(args: argparse.Namespace) -> int:
|
|
|
293
300
|
v = "(version check failed)"
|
|
294
301
|
line("ok", f"{cli_id:<14} {v}")
|
|
295
302
|
else:
|
|
296
|
-
line("
|
|
297
|
-
|
|
303
|
+
line("info" if is_optional else "warn",
|
|
304
|
+
f"{cli_id:<14} (not on PATH{', optional' if is_optional else ''})")
|
|
305
|
+
# GLM SDK is a Python import — also OPTIONAL (only used when the user
|
|
306
|
+
# opts into a GLM provider; flagging it as warn every install is wrong).
|
|
298
307
|
try:
|
|
299
308
|
import importlib
|
|
300
309
|
importlib.import_module("zhipuai")
|
|
301
310
|
line("ok", "glm_sdk (zhipuai Python SDK importable)")
|
|
302
311
|
any_cli = True
|
|
303
312
|
except ImportError:
|
|
304
|
-
line("
|
|
313
|
+
line("info", "glm_sdk (not installed, optional — "
|
|
314
|
+
"`uv tool install zhipuai`)")
|
|
305
315
|
if not any_cli:
|
|
316
|
+
# Only flag PARTIAL when literally ZERO LLM CLI is present — at
|
|
317
|
+
# that point the system has no model to talk to.
|
|
306
318
|
line("warn", "no LLM CLI installed — `omega upgrade` or re-run "
|
|
307
319
|
"install.sh with the llm_clis: block")
|
|
308
320
|
|
|
@@ -324,12 +336,29 @@ def cmd_doctor(args: argparse.Namespace) -> int:
|
|
|
324
336
|
line("ok" if dm == "bypassPermissions" else "warn",
|
|
325
337
|
f"permissions.defaultMode: {dm or 'default'}")
|
|
326
338
|
stop_hooks = (data.get("hooks") or {}).get("Stop") or []
|
|
339
|
+
# Accept the gate as wired if EITHER the `tag` is still ours
|
|
340
|
+
# OR ANY Stop hook commands `omega audit gate` (Claude Code
|
|
341
|
+
# may strip the custom `tag` field on its own rewrites of the
|
|
342
|
+
# settings file — content match is more resilient).
|
|
343
|
+
def _is_gate(entry: dict) -> bool:
|
|
344
|
+
if entry.get("tag") == "omega-audit-gate":
|
|
345
|
+
return True
|
|
346
|
+
for h in (entry.get("hooks") or []):
|
|
347
|
+
if not isinstance(h, dict):
|
|
348
|
+
continue
|
|
349
|
+
cmd = h.get("command", "")
|
|
350
|
+
args = h.get("args") or []
|
|
351
|
+
if cmd.endswith("/omega") and "gate" in args:
|
|
352
|
+
return True
|
|
353
|
+
return False
|
|
327
354
|
has_gate = any(
|
|
328
|
-
isinstance(e, dict) and e
|
|
329
|
-
for e in stop_hooks
|
|
355
|
+
isinstance(e, dict) and _is_gate(e) for e in stop_hooks
|
|
330
356
|
)
|
|
331
|
-
|
|
332
|
-
|
|
357
|
+
# Demoted to "info" when missing — the gate is an
|
|
358
|
+
# opt-in safety net, not a hard requirement. Doctor no
|
|
359
|
+
# longer drops to PARTIAL just because the hook isn't there.
|
|
360
|
+
line("ok" if has_gate else "info",
|
|
361
|
+
f"Stop-hook audit gate: {'wired' if has_gate else 'not wired (optional)'}")
|
|
333
362
|
except Exception as exc: # noqa: BLE001
|
|
334
363
|
line("warn", f"settings.json unreadable: {exc}")
|
|
335
364
|
|
|
Binary file
|
|
@@ -153,33 +153,46 @@ def _route_one(
|
|
|
153
153
|
"""
|
|
154
154
|
from omega_engine import telegram_history
|
|
155
155
|
|
|
156
|
-
# DM (no topic) —
|
|
157
|
-
#
|
|
158
|
-
#
|
|
156
|
+
# DM (no topic) — route to the AISB conversational agent (same one
|
|
157
|
+
# the tmux REPL talks to). This used to refuse with "Missions only
|
|
158
|
+
# run from a project topic" which broke the most basic UX (a fresh
|
|
159
|
+
# install has no group topic yet, so the bot was effectively dead).
|
|
160
|
+
#
|
|
161
|
+
# Per-chat conversation history is namespaced by chat_id (encoded
|
|
162
|
+
# as a negative topic_id to avoid collisions with real Telegram
|
|
163
|
+
# forum topics, which are always positive small integers).
|
|
159
164
|
if topic_id is None:
|
|
160
|
-
|
|
161
|
-
# bot's eventual reply (handled elsewhere) are linked.
|
|
165
|
+
dm_topic = -abs(int(chat_id)) if chat_id is not None else 0
|
|
162
166
|
telegram_history.record_inbound(
|
|
163
|
-
home, topic_id=
|
|
167
|
+
home, topic_id=dm_topic, text=text, message_id=message_id,
|
|
164
168
|
)
|
|
165
169
|
logger.info(
|
|
166
|
-
"telegram in: DM (chat=%s) text=%r —
|
|
167
|
-
"mission from the DM; ask in a project topic instead",
|
|
170
|
+
"telegram in: DM (chat=%s) text=%r — routing to AISB chat",
|
|
168
171
|
chat_id, text[:80],
|
|
169
172
|
)
|
|
173
|
+
try:
|
|
174
|
+
from omega_engine.aisb_chat import chat_once
|
|
175
|
+
reply = chat_once(home, text, topic_id=dm_topic,
|
|
176
|
+
record_history=False)
|
|
177
|
+
except Exception as exc: # noqa: BLE001
|
|
178
|
+
logger.warning("telegram DM: chat_once failed",
|
|
179
|
+
exc_info=True)
|
|
180
|
+
reply = (
|
|
181
|
+
f"I hit an error talking to the AISB agent: {exc}\n"
|
|
182
|
+
"Check `omega doctor` for provider/account status."
|
|
183
|
+
)
|
|
184
|
+
telegram_history.record_outbound(
|
|
185
|
+
home, topic_id=dm_topic, text=reply,
|
|
186
|
+
)
|
|
170
187
|
if telegram_bridge is not None and chat_id is not None:
|
|
171
188
|
try:
|
|
172
189
|
telegram_bridge._call("sendMessage", { # noqa: SLF001
|
|
173
190
|
"chat_id": str(chat_id),
|
|
174
|
-
"text":
|
|
175
|
-
"Missions only run from a project topic in the "
|
|
176
|
-
"OmegaOS group — not the DM. Open the topic for "
|
|
177
|
-
"the project and re-send your request there."
|
|
178
|
-
),
|
|
191
|
+
"text": reply[:3900],
|
|
179
192
|
})
|
|
180
193
|
except Exception: # noqa: BLE001
|
|
181
194
|
logger.warning("telegram daemon: DM reply failed", exc_info=True)
|
|
182
|
-
return "dm:
|
|
195
|
+
return "dm:aisb-chat"
|
|
183
196
|
|
|
184
197
|
# Topic message — record + route.
|
|
185
198
|
telegram_history.record_inbound(
|
|
Binary file
|
|
@@ -176,6 +176,35 @@ def _backend_supabase_stack() -> Stack:
|
|
|
176
176
|
)
|
|
177
177
|
|
|
178
178
|
|
|
179
|
+
def _claude_dashboard_stack() -> Stack:
|
|
180
|
+
"""The Claude Code-grade premium dashboard stack.
|
|
181
|
+
|
|
182
|
+
Picks up the architecture contract from
|
|
183
|
+
``Agentik_SSOT/docs/references/CLAUDE-DESKTOP-FRONTEND-ARCHITECTURE.md``
|
|
184
|
+
during PRD + branding + design-system phases. Worker prompts include
|
|
185
|
+
the `/desktop-architecture` skill so every generated component traces
|
|
186
|
+
back to the same reference doc.
|
|
187
|
+
"""
|
|
188
|
+
return Stack(
|
|
189
|
+
id="claude-dashboard",
|
|
190
|
+
title="Claude-grade premium dashboard (Next.js + Convex + shadcn + Motion + references doc)",
|
|
191
|
+
config=StackConfig(
|
|
192
|
+
type="web",
|
|
193
|
+
frontend="nextjs",
|
|
194
|
+
backend="convex",
|
|
195
|
+
deploy="vercel",
|
|
196
|
+
payments="stripe",
|
|
197
|
+
ui_kit="shadcn",
|
|
198
|
+
auth="clerk",
|
|
199
|
+
extras=["desktop-architecture-reference"],
|
|
200
|
+
),
|
|
201
|
+
why="When the operator wants the Claude / Linear / Vercel / Stripe / "
|
|
202
|
+
"Elevenlabs dashboard look. Genesis phases pull from "
|
|
203
|
+
"Agentik_SSOT/docs/references/CLAUDE-DESKTOP-FRONTEND-ARCHITECTURE.md "
|
|
204
|
+
"as the single source of design truth.",
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
|
|
179
208
|
CANONICAL_STACKS: dict[str, Stack] = {
|
|
180
209
|
s.id: s for s in (
|
|
181
210
|
default_stack(),
|
|
@@ -183,6 +212,7 @@ CANONICAL_STACKS: dict[str, Stack] = {
|
|
|
183
212
|
_mobile_cross_stack(),
|
|
184
213
|
_desktop_tauri_stack(),
|
|
185
214
|
_backend_supabase_stack(),
|
|
215
|
+
_claude_dashboard_stack(),
|
|
186
216
|
)
|
|
187
217
|
}
|
|
188
218
|
|
package/omega/Agentik_Engine/tests/__pycache__/test_install_steps.cpython-313-pytest-8.4.2.pyc
CHANGED
|
Binary file
|
|
Binary file
|
package/omega/Agentik_Engine/tests/__pycache__/test_telegram_history.cpython-313-pytest-8.4.2.pyc
CHANGED
|
Binary file
|
|
Binary file
|
|
@@ -319,7 +319,10 @@ class TestDoctorJSON(unittest.TestCase):
|
|
|
319
319
|
self.assertIn("section", r)
|
|
320
320
|
self.assertIn("status", r)
|
|
321
321
|
self.assertIn("msg", r)
|
|
322
|
-
|
|
322
|
+
# "info" added in v0.19.12 for genuinely optional checks
|
|
323
|
+
# that should not drag READY → PARTIAL (e.g. optional
|
|
324
|
+
# LLM CLIs the user did not opt into).
|
|
325
|
+
self.assertIn(r["status"], {"ok", "warn", "FAIL", "info"})
|
|
323
326
|
|
|
324
327
|
|
|
325
328
|
class TestInstallerWiring(unittest.TestCase):
|
|
@@ -142,10 +142,15 @@ class TestTopicStats(unittest.TestCase):
|
|
|
142
142
|
self.assertEqual(by_topic[2]["messages"], 1)
|
|
143
143
|
|
|
144
144
|
|
|
145
|
-
class
|
|
146
|
-
"""The daemon
|
|
147
|
-
|
|
148
|
-
|
|
145
|
+
class TestDaemonDMRoutesToAISBChat(unittest.TestCase):
|
|
146
|
+
"""The daemon now routes DMs to the AISB conversational agent
|
|
147
|
+
(v0.19.13 change). Previously it refused with "project topic only",
|
|
148
|
+
which made the bot mute on a fresh install with no group yet."""
|
|
149
|
+
|
|
150
|
+
def test_dm_message_routes_to_aisb_chat(self):
|
|
151
|
+
from omega_engine.daemons import telegram as T
|
|
152
|
+
from omega_engine import aisb_chat
|
|
153
|
+
from unittest import mock
|
|
149
154
|
|
|
150
155
|
class _FakeBridge:
|
|
151
156
|
def __init__(self):
|
|
@@ -161,22 +166,65 @@ class TestDaemonDMRefusal(unittest.TestCase):
|
|
|
161
166
|
with tempfile.TemporaryDirectory() as td:
|
|
162
167
|
home = Path(td)
|
|
163
168
|
bridge = _FakeBridge()
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
169
|
+
with mock.patch.object(aisb_chat, "chat_once",
|
|
170
|
+
return_value="hello from AISB"):
|
|
171
|
+
tag = T._route_one(
|
|
172
|
+
topic_id=None, text="hi from DM",
|
|
173
|
+
message_id=5, chat_id=12345,
|
|
174
|
+
supervisor=_FakeSupervisor(),
|
|
175
|
+
project_map={},
|
|
176
|
+
home=home,
|
|
177
|
+
telegram_bridge=bridge,
|
|
178
|
+
)
|
|
179
|
+
self.assertEqual(tag, "dm:aisb-chat",
|
|
180
|
+
"DM must now be tagged as routed to AISB, not refused")
|
|
181
|
+
# We sent the AISB reply back via sendMessage.
|
|
174
182
|
self.assertEqual(len(bridge.calls), 1)
|
|
175
183
|
self.assertEqual(bridge.calls[0]["method"], "sendMessage")
|
|
176
184
|
self.assertEqual(
|
|
177
185
|
str(bridge.calls[0]["fields"]["chat_id"]), "12345",
|
|
178
186
|
)
|
|
179
|
-
self.
|
|
187
|
+
self.assertEqual(
|
|
188
|
+
bridge.calls[0]["fields"]["text"], "hello from AISB",
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
def test_dm_history_is_namespaced_by_chat_id(self):
|
|
192
|
+
"""Two DMs from different chats must NOT cross-contaminate history.
|
|
193
|
+
We use negative topic_ids derived from chat_id (real topics are
|
|
194
|
+
always positive Telegram forum thread IDs)."""
|
|
195
|
+
from omega_engine.daemons import telegram as T
|
|
196
|
+
from omega_engine import aisb_chat
|
|
197
|
+
from unittest import mock
|
|
198
|
+
|
|
199
|
+
class _FakeBridge:
|
|
200
|
+
def __init__(self): self.calls = []
|
|
201
|
+
def _call(self, method, fields, **_kw):
|
|
202
|
+
self.calls.append({"method": method, "fields": fields})
|
|
203
|
+
return {"message_id": 1}
|
|
204
|
+
|
|
205
|
+
class _FakeSupervisor:
|
|
206
|
+
def on_channel_message(self, t, x): return []
|
|
207
|
+
|
|
208
|
+
with tempfile.TemporaryDirectory() as td:
|
|
209
|
+
home = Path(td)
|
|
210
|
+
(home / "Agentik_Runtime").mkdir(parents=True)
|
|
211
|
+
captured: list[int] = []
|
|
212
|
+
def _fake_chat(home_arg, text, *, topic_id, record_history):
|
|
213
|
+
captured.append(topic_id)
|
|
214
|
+
return "ok"
|
|
215
|
+
with mock.patch.object(aisb_chat, "chat_once",
|
|
216
|
+
side_effect=_fake_chat):
|
|
217
|
+
T._route_one(topic_id=None, text="hi", message_id=1,
|
|
218
|
+
chat_id=42, supervisor=_FakeSupervisor(),
|
|
219
|
+
project_map={}, home=home,
|
|
220
|
+
telegram_bridge=_FakeBridge())
|
|
221
|
+
T._route_one(topic_id=None, text="hi", message_id=2,
|
|
222
|
+
chat_id=99, supervisor=_FakeSupervisor(),
|
|
223
|
+
project_map={}, home=home,
|
|
224
|
+
telegram_bridge=_FakeBridge())
|
|
225
|
+
self.assertEqual(captured, [-42, -99],
|
|
226
|
+
"DM history must be namespaced by chat_id "
|
|
227
|
+
"(encoded as negative topic_id)")
|
|
180
228
|
|
|
181
229
|
def test_topic_message_records_history(self):
|
|
182
230
|
from omega_engine.daemons.telegram import _route_one
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.19.
|
|
1
|
+
0.19.13
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# References
|
|
2
|
+
|
|
3
|
+
Operator-curated source-of-truth documents that OmegaOS skills + Genesis
|
|
4
|
+
consume by name. Drop a new version of any file here and it propagates
|
|
5
|
+
to every project at the next `omega sync`.
|
|
6
|
+
|
|
7
|
+
## Active references
|
|
8
|
+
|
|
9
|
+
| File | Consumed by | Topic |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| `CLAUDE-DESKTOP-FRONTEND-ARCHITECTURE.md` | `/desktop-architecture`, Genesis stack `claude-dashboard`, refonte audit | Premium desktop / dashboard UI architecture, the "Claude / Linear / Vercel / Stripe / Elevenlabs" canon |
|
|
12
|
+
|
|
13
|
+
## Format
|
|
14
|
+
|
|
15
|
+
Plain Markdown. No frontmatter needed — these are reference docs, not
|
|
16
|
+
SKILL.md. Headings should be self-describing so skills can extract
|
|
17
|
+
sub-sections by regex if needed.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: desktop-architecture
|
|
3
|
+
description: >
|
|
4
|
+
Reference skill — pull the canonical Claude Code-grade desktop/dashboard
|
|
5
|
+
architecture (`Agentik_SSOT/docs/references/CLAUDE-DESKTOP-FRONTEND-ARCHITECTURE.md`)
|
|
6
|
+
and apply it to a project. Triggers on "desktop architecture", "Claude
|
|
7
|
+
dashboard", "Claude desktop", "premium dashboard", "comme Linear / Vercel
|
|
8
|
+
/ Stripe / Elevenlabs", "dashboard senior", "claude stack". Use whenever
|
|
9
|
+
the user asks for a dashboard refonte or a new project that needs the
|
|
10
|
+
Claude-grade desktop look.
|
|
11
|
+
when_to_use: >
|
|
12
|
+
User mentions "desktop architecture", "Claude dashboard", "Claude desktop
|
|
13
|
+
stack", or asks for a dashboard rebuild "comme Claude / Linear / Vercel /
|
|
14
|
+
Stripe / Elevenlabs". Also triggers automatically when the Genesis stack
|
|
15
|
+
picker selects the `claude-dashboard` preset.
|
|
16
|
+
allowed-tools: Read Grep Glob
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# /desktop-architecture — pull the canonical Claude dashboard reference
|
|
20
|
+
|
|
21
|
+
This skill loads the **Claude Desktop Frontend Architecture** reference
|
|
22
|
+
document from the SSOT and applies its principles to the current task.
|
|
23
|
+
|
|
24
|
+
## What it does
|
|
25
|
+
|
|
26
|
+
1. Reads `$OMEGA_HOME/Agentik_SSOT/docs/references/CLAUDE-DESKTOP-FRONTEND-ARCHITECTURE.md`
|
|
27
|
+
2. Extracts the relevant section (components, layout, motion, palette,
|
|
28
|
+
typography, density, navigation, command palette, etc.)
|
|
29
|
+
3. Applies it as the design contract for the requested task:
|
|
30
|
+
- **Refonte audit** — score the current UI against this contract
|
|
31
|
+
- **Genesis** — when stack = `claude-dashboard`, the PRD, branding and
|
|
32
|
+
design-system phases derive their tokens from this doc
|
|
33
|
+
- **Component builder** — when a worker generates a new dashboard
|
|
34
|
+
screen, it references the layout primitives from this doc first
|
|
35
|
+
|
|
36
|
+
## Triggers (any of these in a user prompt invoke me)
|
|
37
|
+
|
|
38
|
+
- `desktop architecture`
|
|
39
|
+
- `Claude desktop` / `Claude dashboard` / `Claude stack`
|
|
40
|
+
- `premium dashboard` / `dashboard senior`
|
|
41
|
+
- `comme Linear` / `comme Vercel` / `comme Stripe` / `comme Elevenlabs`
|
|
42
|
+
- `refais le dashboard` / `redesign dashboard` (combined with project name)
|
|
43
|
+
|
|
44
|
+
## Where it lives
|
|
45
|
+
|
|
46
|
+
The reference doc itself lives at:
|
|
47
|
+
`$OMEGA_HOME/Agentik_SSOT/docs/references/CLAUDE-DESKTOP-FRONTEND-ARCHITECTURE.md`
|
|
48
|
+
|
|
49
|
+
It's the single source of truth — when Gareth refreshes the document
|
|
50
|
+
(e.g. new components, new motion language), every project re-reads it
|
|
51
|
+
on next `/desktop-architecture` invocation. No fork, no drift.
|
|
52
|
+
|
|
53
|
+
## How to refresh the reference
|
|
54
|
+
|
|
55
|
+
The operator drops a new version into the SSOT path above, then runs:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
omega sync # projects to ~/.claude/skills/<id>/
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Workers spawned after the sync pick up the new content automatically.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentikos/omega-os",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.13",
|
|
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"
|