omnilane 0.7.0
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/CHANGELOG.md +209 -0
- package/LICENSE +21 -0
- package/README.ja.md +345 -0
- package/README.ko.md +337 -0
- package/README.md +368 -0
- package/README.zh-CN.md +317 -0
- package/README.zh-TW.md +327 -0
- package/SECURITY.md +37 -0
- package/VERSION +1 -0
- package/bin/omnilane +72 -0
- package/completions/_omnilane +114 -0
- package/completions/omnilane.bash +123 -0
- package/local.sh.example +37 -0
- package/package.json +54 -0
- package/routing.local.yaml.example +41 -0
- package/routing.yaml +34 -0
- package/scripts/configure.sh +134 -0
- package/scripts/dispatch.sh +705 -0
- package/scripts/doctor.sh +166 -0
- package/scripts/jobs.sh +802 -0
- package/scripts/lib/common.sh +247 -0
- package/scripts/lib/i18n.sh +104 -0
- package/scripts/lib/job-timeout.pl +109 -0
- package/scripts/lib/job-worker.sh +23 -0
- package/scripts/release-audit.sh +314 -0
- package/scripts/runners/run-claude.sh +37 -0
- package/scripts/runners/run-codex.sh +51 -0
- package/scripts/runners/run-exec.sh +33 -0
- package/scripts/runners/run-gemini.sh +60 -0
- package/scripts/runners/run-grok.sh +56 -0
- package/scripts/runners/run-vote.sh +119 -0
- package/scripts/ui.py +1236 -0
- package/ui/app.js +1106 -0
- package/ui/index.html +192 -0
- package/ui/styles.css +1023 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -u
|
|
3
|
+
# Read-only health report for routing, state, watchdog, and optional UI support.
|
|
4
|
+
|
|
5
|
+
JSON_MODE=0
|
|
6
|
+
if [[ $# -eq 1 && "$1" == "--json" ]]; then
|
|
7
|
+
JSON_MODE=1
|
|
8
|
+
elif [[ $# -ne 0 ]]; then
|
|
9
|
+
echo "usage: omnilane doctor [--json]" >&2
|
|
10
|
+
exit 2
|
|
11
|
+
fi
|
|
12
|
+
REPO="${OMNILANE_DOCTOR_REPO:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
|
|
13
|
+
OMNILANE_HOME="${OMNILANE_HOME:-$HOME/.omnilane}"
|
|
14
|
+
PASS_COUNT=0
|
|
15
|
+
WARN_COUNT=0
|
|
16
|
+
FAIL_COUNT=0
|
|
17
|
+
JSON_REPORTS=""
|
|
18
|
+
JSON_FIRST=1
|
|
19
|
+
|
|
20
|
+
json_escape() {
|
|
21
|
+
local s="$1" out="" ch escaped code i
|
|
22
|
+
for ((i = 0; i < ${#s}; i++)); do
|
|
23
|
+
ch="${s:i:1}"
|
|
24
|
+
case "$ch" in
|
|
25
|
+
'"') out="$out\\\"" ;;
|
|
26
|
+
'\\') out="$out\\\\" ;;
|
|
27
|
+
$'\b') out="$out\\b" ;;
|
|
28
|
+
$'\f') out="$out\\f" ;;
|
|
29
|
+
$'\n') out="$out\\n" ;;
|
|
30
|
+
$'\r') out="$out\\r" ;;
|
|
31
|
+
$'\t') out="$out\\t" ;;
|
|
32
|
+
*)
|
|
33
|
+
LC_CTYPE=C printf -v code '%d' "'$ch"
|
|
34
|
+
if [[ "$code" -ge 0 && "$code" -lt 32 ]]; then
|
|
35
|
+
printf -v escaped '\\u%04x' "$code"
|
|
36
|
+
out="$out$escaped"
|
|
37
|
+
else
|
|
38
|
+
out="$out$ch"
|
|
39
|
+
fi
|
|
40
|
+
;;
|
|
41
|
+
esac
|
|
42
|
+
done
|
|
43
|
+
printf '%s' "$out"
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
report() {
|
|
47
|
+
local level="$1" check="$2" message="$3"
|
|
48
|
+
# Diagnostic inputs include user-controlled paths and routing errors. Strip
|
|
49
|
+
# terminal control bytes so a failed check cannot forge the report display.
|
|
50
|
+
message="$(printf '%s' "$message" | LC_ALL=C tr -d '\000-\010\013\014\016-\037\177')"
|
|
51
|
+
if [[ "$JSON_MODE" -eq 1 ]]; then
|
|
52
|
+
[[ "$JSON_FIRST" -eq 1 ]] || JSON_REPORTS="$JSON_REPORTS,"
|
|
53
|
+
JSON_FIRST=0
|
|
54
|
+
JSON_REPORTS="$JSON_REPORTS{\"level\":\"$(json_escape "$level")\",\"check\":\"$(json_escape "$check")\",\"message\":\"$(json_escape "$message")\"}"
|
|
55
|
+
else
|
|
56
|
+
printf '%-5s %-12s %s\n' "$level" "$check" "$message"
|
|
57
|
+
fi
|
|
58
|
+
case "$level" in
|
|
59
|
+
PASS) PASS_COUNT=$((PASS_COUNT + 1)) ;;
|
|
60
|
+
WARN) WARN_COUNT=$((WARN_COUNT + 1)) ;;
|
|
61
|
+
FAIL) FAIL_COUNT=$((FAIL_COUNT + 1)) ;;
|
|
62
|
+
esac
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
DISPATCH="$REPO/scripts/dispatch.sh"
|
|
66
|
+
if [[ -x "$DISPATCH" ]]; then
|
|
67
|
+
report PASS dispatch "$DISPATCH is executable"
|
|
68
|
+
else
|
|
69
|
+
report FAIL dispatch "$DISPATCH is missing or not executable"
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
if [[ -r "$REPO/routing.yaml" ]]; then
|
|
73
|
+
report PASS config "$REPO/routing.yaml is readable"
|
|
74
|
+
else
|
|
75
|
+
report FAIL config "$REPO/routing.yaml is missing or unreadable"
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
if [[ -x "$DISPATCH" ]]; then
|
|
79
|
+
route_output="$(OMNILANE_HOME="$OMNILANE_HOME" /bin/bash "$DISPATCH" --list 2>&1)"
|
|
80
|
+
route_rc=$?
|
|
81
|
+
route_count="$(printf '%s\n' "$route_output" | awk 'NF { count++ } END { print count + 0 }')"
|
|
82
|
+
usable_count="$(printf '%s\n' "$route_output" | awk \
|
|
83
|
+
'NF && $0 !~ /unavailable/ && $0 !~ /^[^:]+:[[:space:]]+off([[:space:]]|$)/ { count++ } END { print count + 0 }')"
|
|
84
|
+
if [[ "$route_rc" -ne 0 ]]; then
|
|
85
|
+
first_error="$(printf '%s\n' "$route_output" | sed -n '1p')"
|
|
86
|
+
report FAIL routing "effective routing failed: ${first_error:-unknown error}"
|
|
87
|
+
elif [[ "$route_count" -eq 0 ]]; then
|
|
88
|
+
report FAIL routing "effective routing is empty"
|
|
89
|
+
elif [[ "$usable_count" -eq 0 ]]; then
|
|
90
|
+
report WARN routing "$route_count lanes parsed, but none is currently usable"
|
|
91
|
+
else
|
|
92
|
+
report PASS routing "$route_count lanes parsed; $usable_count currently usable"
|
|
93
|
+
fi
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
if [[ ! -e "$OMNILANE_HOME" ]]; then
|
|
97
|
+
report WARN state "$OMNILANE_HOME does not exist yet; doctor left it unchanged"
|
|
98
|
+
elif [[ ! -d "$OMNILANE_HOME" ]]; then
|
|
99
|
+
report FAIL state "$OMNILANE_HOME exists but is not a directory"
|
|
100
|
+
elif [[ ! -r "$OMNILANE_HOME" || ! -w "$OMNILANE_HOME" || ! -x "$OMNILANE_HOME" ]]; then
|
|
101
|
+
report FAIL state "$OMNILANE_HOME is not readable, writable, and searchable"
|
|
102
|
+
else
|
|
103
|
+
report PASS state "$OMNILANE_HOME is accessible"
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
if [[ -f "$OMNILANE_HOME/local.sh" ]]; then
|
|
107
|
+
if /bin/bash -n "$OMNILANE_HOME/local.sh" 2>/dev/null; then
|
|
108
|
+
report PASS local-config "$OMNILANE_HOME/local.sh syntax is valid"
|
|
109
|
+
else
|
|
110
|
+
report FAIL local-config "$OMNILANE_HOME/local.sh has invalid Bash syntax"
|
|
111
|
+
fi
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
if [[ -L "$OMNILANE_HOME/jobs" ||
|
|
115
|
+
( -e "$OMNILANE_HOME/jobs" && ! -d "$OMNILANE_HOME/jobs" ) ]]; then
|
|
116
|
+
report FAIL job-privacy "$OMNILANE_HOME/jobs must be a real directory, not a symlink or file"
|
|
117
|
+
elif [[ -d "$OMNILANE_HOME/jobs" ]]; then
|
|
118
|
+
jobs_mode="$(stat -f '%Lp' "$OMNILANE_HOME/jobs" 2>/dev/null || stat -c '%a' "$OMNILANE_HOME/jobs" 2>/dev/null || true)"
|
|
119
|
+
if [[ "$jobs_mode" =~ ^[0-7]*00$ ]]; then
|
|
120
|
+
report PASS job-privacy "$OMNILANE_HOME/jobs mode is $jobs_mode"
|
|
121
|
+
elif [[ -n "$jobs_mode" ]]; then
|
|
122
|
+
report WARN job-privacy "$OMNILANE_HOME/jobs mode is $jobs_mode; owner-only 700 is safer"
|
|
123
|
+
else
|
|
124
|
+
report WARN job-privacy "could not determine $OMNILANE_HOME/jobs permissions"
|
|
125
|
+
fi
|
|
126
|
+
fi
|
|
127
|
+
|
|
128
|
+
if [[ -L "$OMNILANE_HOME/locks" ||
|
|
129
|
+
( -e "$OMNILANE_HOME/locks" && ! -d "$OMNILANE_HOME/locks" ) ]]; then
|
|
130
|
+
report FAIL lock-store "$OMNILANE_HOME/locks must be a real directory, not a symlink or file"
|
|
131
|
+
fi
|
|
132
|
+
|
|
133
|
+
if command -v timeout >/dev/null 2>&1; then
|
|
134
|
+
report PASS watchdog "timeout is available"
|
|
135
|
+
elif command -v gtimeout >/dev/null 2>&1; then
|
|
136
|
+
report PASS watchdog "gtimeout is available"
|
|
137
|
+
elif command -v perl >/dev/null 2>&1; then
|
|
138
|
+
report PASS watchdog "Perl alarm fallback is available"
|
|
139
|
+
else
|
|
140
|
+
report FAIL watchdog "timeout, gtimeout, and perl are all unavailable"
|
|
141
|
+
fi
|
|
142
|
+
|
|
143
|
+
if command -v python3 >/dev/null 2>&1; then
|
|
144
|
+
if python3 -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 9) else 1)' \
|
|
145
|
+
>/dev/null 2>&1; then
|
|
146
|
+
python_version="$(python3 -c 'import platform; print(platform.python_version())')"
|
|
147
|
+
report PASS live-ui "Python $python_version supports the optional UI"
|
|
148
|
+
else
|
|
149
|
+
report WARN live-ui "Python 3.9 or newer is required for the optional UI"
|
|
150
|
+
fi
|
|
151
|
+
else
|
|
152
|
+
report WARN live-ui "python3 is absent; model routing still works"
|
|
153
|
+
fi
|
|
154
|
+
|
|
155
|
+
if [[ "$JSON_MODE" -eq 1 ]]; then
|
|
156
|
+
ok=true
|
|
157
|
+
[[ "$FAIL_COUNT" -eq 0 ]] || ok=false
|
|
158
|
+
printf '{"ok":%s,"checks":[%s],"summary":{"passed":%s,"warnings":%s,"failed":%s}}\n' \
|
|
159
|
+
"$ok" "$JSON_REPORTS" "$PASS_COUNT" "$WARN_COUNT" "$FAIL_COUNT"
|
|
160
|
+
else
|
|
161
|
+
warning_suffix=s
|
|
162
|
+
[[ "$WARN_COUNT" -eq 1 ]] && warning_suffix=""
|
|
163
|
+
printf '\nSummary: %s passed, %s warning%s, %s failed\n' \
|
|
164
|
+
"$PASS_COUNT" "$WARN_COUNT" "$warning_suffix" "$FAIL_COUNT"
|
|
165
|
+
fi
|
|
166
|
+
[[ "$FAIL_COUNT" -eq 0 ]]
|