forked from BasedHardware/omi
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathomi-ctl
More file actions
executable file
·184 lines (175 loc) · 7.17 KB
/
Copy pathomi-ctl
File metadata and controls
executable file
·184 lines (175 loc) · 7.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#!/bin/bash
# omi-ctl — drive the running Omi desktop app via its local automation bridge.
#
# The bridge (DesktopAutomationBridge.swift) auto-enables on every non-production
# bundle and listens on 127.0.0.1:47777. It lets an agent jump straight to any
# screen and read app state without clicking through the UI.
#
# Env: OMI_AUTOMATION_PORT (default 47777) — set this per bundle if running
# several named test bundles side-by-side (each needs its own port).
# OMI_AUTOMATION_TOKEN can override the per-launch token file.
set -euo pipefail
PORT="${OMI_AUTOMATION_PORT:-47777}"
BASE="http://127.0.0.1:${PORT}"
TOKEN="${OMI_AUTOMATION_TOKEN:-}"
# shellcheck source=automation-token-path.sh
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/automation-token-path.sh"
TOKEN_FILE="$(omi_automation_token_file "$PORT")"
load_token() {
if [ -z "$TOKEN" ] && [ -f "$TOKEN_FILE" ]; then
TOKEN="$(tr -d '\r\n' < "$TOKEN_FILE")"
fi
if [ -z "$TOKEN" ]; then
echo "omi-ctl: missing automation token; set OMI_AUTOMATION_TOKEN or wait for $TOKEN_FILE" >&2
exit 1
fi
}
curl_bridge() {
load_token
curl -fsS -H "Authorization: Bearer $TOKEN" "$@"
}
cmd="${1:-help}"; shift || true
case "$cmd" in
state)
curl_bridge "$BASE/state"; echo ;;
health)
# Health intentionally uses the unauthenticated identity route so callers
# see backend and negotiated runtime diagnostics, not the auth-only state
# snapshot served at the same path.
curl -fsS "$BASE/health"; echo ;;
log-path)
curl -fsS "$BASE/health" | python3 -c '
import json, sys
health = json.load(sys.stdin)
path = health.get("logFilePath")
if not isinstance(path, str) or not path:
raise SystemExit("omi-ctl: health did not provide logFilePath")
print(path)
' ;;
navigate)
target="${1:?usage: omi-ctl navigate <screen> [settings-section] [--show]}"; shift || true
section=""
activate=false
for value in "$@"; do
if [ "$value" = "--show" ]; then
activate=true
elif [ -z "$section" ]; then
section="$value"
else
echo "omi-ctl: unexpected navigate argument: $value" >&2
exit 2
fi
done
body="{\"target\":\"$target\",\"activateApp\":$activate"
[ -n "$section" ] && body="$body,\"settingsSection\":\"$section\""
body="$body}"
curl_bridge -X POST "$BASE/navigate" -d "$body" >/dev/null
# The POST snapshot races the animated tab switch — settle, then report fresh state.
sleep 0.3
curl_bridge "$BASE/state"; echo ;;
ui)
mode="${1:-}"
activate=false
[ "${2:-}" = "--activate" ] && activate=true
params=""
[ -n "$mode" ] && params="\"mode\":\"$mode\",\"activate\":\"$activate\""
body="{\"name\":\"set_automation_ui_presentation\""
[ -n "$params" ] && body="$body,\"params\":{$params}"
body="$body}"
curl_bridge -X POST "$BASE/action" -d "$body"; echo ;;
open-conversation)
id="${1:?usage: omi-ctl open-conversation <id> [--transcript] [--show]}"; shift || true
show=false
activate=false
for value in "$@"; do
case "$value" in
--transcript) show=true ;;
--show) activate=true ;;
*) echo "omi-ctl: unexpected open-conversation argument: $value" >&2; exit 2 ;;
esac
done
curl_bridge -X POST "$BASE/conversation/open" \
-d "{\"conversationId\":\"$id\",\"showTranscript\":$show,\"activateApp\":$activate}"; echo ;;
actions)
curl_bridge "$BASE/actions"; echo ;;
action)
name="${1:?usage: omi-ctl action <name> [key=value ...]}"; shift || true
params=""
for kv in "$@"; do
key="${kv%%=*}"; val="${kv#*=}"
[ -n "$params" ] && params="$params,"
params="$params\"$key\":\"$val\""
done
body="{\"name\":\"$name\""
[ -n "$params" ] && body="$body,\"params\":{$params}"
body="$body}"
curl_bridge -X POST "$BASE/action" -d "$body"; echo ;;
wait-ready)
tries="${1:-30}"
for _ in $(seq 1 "$tries"); do
s=$(curl_bridge "$BASE/state" 2>/dev/null || true)
# `appState: main` is a UI projection, not an authentication guarantee.
# The authenticated state snapshot is the only readiness contract exposed
# by DesktopAutomationBridge: require a live, signed-in, fully-onboarded
# owner snapshot after restoration has completed.
if printf '%s' "$s" | python3 -c '
import json
import sys
try:
envelope = json.load(sys.stdin)
snapshot = envelope["result"]
except (json.JSONDecodeError, KeyError, TypeError):
raise SystemExit(1)
ready = (
envelope.get("ok") is True
and isinstance(snapshot, dict)
and snapshot.get("appState") == "main"
and snapshot.get("isSignedIn") is True
and snapshot.get("hasCompletedOnboarding") is True
and snapshot.get("isRestoringAuth") is False
and snapshot.get("snapshotStale") is False
)
raise SystemExit(0 if ready else 1)
'; then
echo "$s"
exit 0
fi
sleep 0.5
done
echo "omi-ctl: timed out waiting for a live signed-in owner-ready main state" >&2; exit 1 ;;
screens)
# Every token here must resolve in ChatFirstRoute.automationVisibilityDestination. `focus` and
# `insight` were listed after their pages were deleted, so `omi-ctl navigate insight` posted a
# target the app answered "ok" to and then did nothing with — the failure mode the bridge exists
# to avoid. `goals` lost its "(chat-first)" note when the second shell did: there is one shell,
# and `help` opens Settings > About, where getting help from a person lives.
echo "dashboard|home conversations chat memories tasks goals rewind apps|integrations settings permissions help" ;;
*)
cat <<EOF
omi-ctl — drive the Omi desktop app via the local automation bridge
Usage:
omi-ctl state App state snapshot (selected tab, auth, onboarding)
omi-ctl health Bundle, backend, runtime, and exact current log identity
omi-ctl log-path Print the exact current bundle-and-launch app log path
omi-ctl navigate <screen> [section] [--show]
Jump cursor-free; --show brings the app forward
omi-ctl ui [quiet|interactive|normal] [--activate]
Read or change non-production test-window presentation
omi-ctl open-conversation <id> [--transcript] [--show]
omi-ctl wait-ready [tries] Block until a live signed-in owner-ready main state (0.5s/try)
omi-ctl screens List valid screen targets
omi-ctl actions List semantic actions the app exposes
omi-ctl action <name> [key=value ...] Run a semantic action (cursor-free, in-process)
Examples:
omi-ctl navigate rewind
omi-ctl navigate rewind --show # opt in to foreground presentation
omi-ctl ui quiet # park rendered windows out of the way
omi-ctl navigate settings rewind # Settings page, Rewind sub-section
omi-ctl wait-ready && omi-ctl navigate memories
omi-ctl actions # discover available actions
omi-ctl action refresh_all_data
omi-ctl action toggle_transcription enabled=false
Env: OMI_AUTOMATION_PORT (default 47777), OMI_AUTOMATION_TOKEN, OMI_AUTOMATION_TOKEN_FILE
EOF
;;
esac