omnilane 0.42.9 → 0.45.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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +260 -1
- package/README.ja.md +190 -32
- package/README.ko.md +190 -32
- package/README.md +319 -73
- package/README.zh-CN.md +190 -31
- package/README.zh-TW.md +180 -53
- package/VERSION +1 -1
- package/bin/omnilane +29 -0
- package/completions/_omnilane +1 -1
- package/completions/omnilane.bash +1 -1
- package/completions/omnilane.fish +2 -0
- package/config/aa-model-policy.json +1339 -1170
- package/docs/aa-model-coverage-2026-09-05.json +43 -1
- package/docs/model-capabilities-2026-09.md +195 -4
- package/docs/native-executor.md +59 -0
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/routing.yaml +25 -23
- package/scripts/aa_rebaseline.py +409 -0
- package/scripts/configure.sh +1 -1
- package/scripts/dispatch.sh +54 -4
- package/scripts/doctor.sh +7 -1
- package/scripts/lib/aa_lanes.py +135 -0
- package/scripts/lib/aa_policy.py +165 -8
- package/scripts/lib/build_overlay.py +54 -18
- package/scripts/lib/caller_identity.py +75 -13
- package/scripts/lib/cli_provenance.py +82 -0
- package/scripts/lib/native.py +107 -2
- package/scripts/lib/native_context.py +145 -0
- package/scripts/lib/overlay_health.py +24 -2
- package/scripts/lib/probe.py +2 -0
- package/scripts/lib/probe_sweep.py +189 -0
- package/scripts/lib/resign.py +493 -0
- package/scripts/release-audit.sh +31 -0
- package/skills/omnilane/SKILL.md +393 -477
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Probe every selector build_overlay.py knows, one vendor at a time.
|
|
3
|
+
|
|
4
|
+
probe.py runs a single command; this derives the whole set from PROVEN and the
|
|
5
|
+
frozen registry, so a sweep is reproducible on any host without carrying a list
|
|
6
|
+
of commands from the last one. Each vendor is probed independently and reports
|
|
7
|
+
one of three outcomes: done, unprobeable (nobody is logged in, or the session
|
|
8
|
+
cannot reach the keychain), or failed.
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import argparse
|
|
13
|
+
import json
|
|
14
|
+
import os
|
|
15
|
+
import re
|
|
16
|
+
import subprocess
|
|
17
|
+
import sys
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
21
|
+
import build_overlay # noqa: E402
|
|
22
|
+
import probe as probe_module # noqa: E402
|
|
23
|
+
|
|
24
|
+
VENDORS = ("claude", "codex", "gemini", "grok")
|
|
25
|
+
TOKENS = {"claude": "CLAUDE_SELECTOR_OK", "codex": "CODEX_SELECTOR_OK",
|
|
26
|
+
"gemini": "GEMINI_SELECTOR_OK", "grok": "GROK_SELECTOR_OK"}
|
|
27
|
+
# The keychain-backed CLIs cannot authenticate from a launchd Background session
|
|
28
|
+
# (an ssh login is one); probing there records "not logged in" as if it were a
|
|
29
|
+
# finding about the selector.
|
|
30
|
+
KEYCHAIN_VENDORS = ("claude", "gemini", "grok")
|
|
31
|
+
NOT_AUTHENTICATED = re.compile(
|
|
32
|
+
r"not logged in|not signed in|authentication required|please run /login|grok login"
|
|
33
|
+
r"|failed to authenticate|oauth (session|token) (has )?expired|could not be refreshed"
|
|
34
|
+
r"|invalid api key|unauthorized|\b401\b",
|
|
35
|
+
re.IGNORECASE)
|
|
36
|
+
TRANSIENT = re.compile(r"\b(403|429|500|502|503|529)\b|permission-denied|overloaded|timed? ?out",
|
|
37
|
+
re.IGNORECASE)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def prompt(vendor: str) -> str:
|
|
41
|
+
return f"Reply exactly {TOKENS[vendor]}. Do not use tools or delegate."
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def command(vendor: str, model: str, effort: str | None, app_data: str | None = None) -> list[str]:
|
|
45
|
+
text = prompt(vendor)
|
|
46
|
+
if vendor == "claude":
|
|
47
|
+
selector = ["--model", model] + (["--effort", effort] if effort else [])
|
|
48
|
+
return ["claude", "--disable-slash-commands", *selector, "--permission-mode", "dontAsk",
|
|
49
|
+
"--tools", "", "--output-format", "json", "-p", text]
|
|
50
|
+
if vendor == "codex":
|
|
51
|
+
return ["codex", "exec", "--json", "--skip-git-repo-check", "-m", model,
|
|
52
|
+
"-c", f'model_reasoning_effort="{effort or "none"}"',
|
|
53
|
+
"-c", 'approval_policy="never"', "-c", 'sandbox_mode="read-only"', text]
|
|
54
|
+
if vendor == "grok":
|
|
55
|
+
return ["grok", "--no-memory", "--no-subagents", "--no-plan", "--no-alt-screen",
|
|
56
|
+
"--output-format", "json", "--verbatim", "--permission-mode", "dontAsk",
|
|
57
|
+
"--tools", "Read", "--deny", "Bash", "--deny", "Edit", "--disable-web-search",
|
|
58
|
+
"-m", model, "--reasoning-effort", effort or "high", "-p", text]
|
|
59
|
+
if vendor == "gemini":
|
|
60
|
+
return ["agy", f"--app_data_dir={app_data}", "--model", model, "-p", text]
|
|
61
|
+
raise ValueError(f"unsupported vendor: {vendor}")
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def plan(vendor: str) -> list[dict]:
|
|
65
|
+
"""One entry per evidence file this vendor's PROVEN rows point at."""
|
|
66
|
+
entries: dict[str, dict] = {}
|
|
67
|
+
for config_id, (_, runtime_model, evidence) in sorted(build_overlay.PROVEN.items()):
|
|
68
|
+
row = build_overlay.ROWS[config_id]
|
|
69
|
+
if row["vendor"] != vendor or evidence in entries:
|
|
70
|
+
continue
|
|
71
|
+
entries[evidence] = {"name": evidence, "config_id": config_id, "model": runtime_model,
|
|
72
|
+
"effort": None if vendor == "gemini" else row["effort"]}
|
|
73
|
+
return list(entries.values())
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def session_manager(runner=subprocess.run) -> str:
|
|
77
|
+
try:
|
|
78
|
+
return runner(["launchctl", "managername"], capture_output=True, text=True,
|
|
79
|
+
timeout=10).stdout.strip()
|
|
80
|
+
except (OSError, subprocess.SubprocessError):
|
|
81
|
+
return ""
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _text(record: dict) -> str:
|
|
85
|
+
parts = [str(record.get("verdict_reason") or "")]
|
|
86
|
+
for key in ("stdout", "stderr"):
|
|
87
|
+
try:
|
|
88
|
+
parts.append(Path(record[key]).read_text(errors="replace")[:4000])
|
|
89
|
+
except (KeyError, OSError):
|
|
90
|
+
pass
|
|
91
|
+
return "\n".join(parts)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def sweep(vendor: str, root: Path, *, repo: Path = build_overlay.REPO, home: Path | None = None,
|
|
95
|
+
run_probe=probe_module.probe, manager=session_manager, log=print,
|
|
96
|
+
only_missing: bool = False) -> dict:
|
|
97
|
+
"""Probe one vendor into root/evidence. Never raises for a probe that merely failed.
|
|
98
|
+
|
|
99
|
+
only_missing probes just the rows root/evidence has no record for: the
|
|
100
|
+
executable is unchanged, so what it already answered still stands.
|
|
101
|
+
"""
|
|
102
|
+
home = home or Path.home()
|
|
103
|
+
entries = plan(vendor)
|
|
104
|
+
report = {"vendor": vendor, "outcome": "done", "passed": [], "failed": [], "detail": ""}
|
|
105
|
+
if only_missing:
|
|
106
|
+
entries = [entry for entry in entries
|
|
107
|
+
if not (root / "evidence" / f"{entry['name']}.json").is_file()]
|
|
108
|
+
if not entries:
|
|
109
|
+
report["detail"] = "every row already has probe evidence"
|
|
110
|
+
return report
|
|
111
|
+
if (vendor in KEYCHAIN_VENDORS and sys.platform == "darwin"
|
|
112
|
+
and os.environ.get("OMNILANE_PROBE_ANY_SESSION") != "1"):
|
|
113
|
+
name = manager()
|
|
114
|
+
if name and name != "Aqua":
|
|
115
|
+
report.update(outcome="unprobeable",
|
|
116
|
+
detail=(f"this is a launchd {name} session (an ssh login is one); "
|
|
117
|
+
f"{vendor}'s credentials are in the login keychain, which only an "
|
|
118
|
+
"Aqua (GUI) session can read"))
|
|
119
|
+
return report
|
|
120
|
+
work = root / "work"
|
|
121
|
+
work.mkdir(parents=True, exist_ok=True)
|
|
122
|
+
cli = "agy" if vendor == "gemini" else vendor
|
|
123
|
+
for index, entry in enumerate(entries):
|
|
124
|
+
app_root = None
|
|
125
|
+
app_data = None
|
|
126
|
+
if vendor == "gemini":
|
|
127
|
+
# prepare-agy-mode binds its private root to one workdir, so it is per sweep.
|
|
128
|
+
app_root = home / ".omnilane" / "agy-app" / f"probe-{root.name}-{entry['name']}"
|
|
129
|
+
prepared = subprocess.run(
|
|
130
|
+
[sys.executable, str(repo / "scripts/lib/prepare-agy-mode.py"), "--mode", "advise",
|
|
131
|
+
"--workdir", str(work), "--app-root", str(app_root),
|
|
132
|
+
"--gemini-dir", str(home / ".gemini")],
|
|
133
|
+
capture_output=True, text=True)
|
|
134
|
+
if prepared.returncode != 0:
|
|
135
|
+
report.update(outcome="failed",
|
|
136
|
+
detail=f"prepare-agy-mode failed: {prepared.stderr.strip()[-200:]}")
|
|
137
|
+
return report
|
|
138
|
+
app_data = prepared.stdout.strip()
|
|
139
|
+
argv = command(vendor, entry["model"], entry["effort"], app_data)
|
|
140
|
+
record = {}
|
|
141
|
+
for attempt in (1, 2):
|
|
142
|
+
record = run_probe(entry["name"], argv, root=root, vendor=cli,
|
|
143
|
+
expected_token=TOKENS[vendor], app_root=app_root)
|
|
144
|
+
if record.get("verdict") == "pass" or attempt == 2 or not TRANSIENT.search(_text(record)):
|
|
145
|
+
break
|
|
146
|
+
log(f"{entry['name']}: transient failure, retrying once")
|
|
147
|
+
if record.get("verdict") == "pass":
|
|
148
|
+
report["passed"].append(entry["config_id"])
|
|
149
|
+
log(f"{entry['name']} pass {record.get('evidence_tier')}")
|
|
150
|
+
continue
|
|
151
|
+
if NOT_AUTHENTICATED.search(_text(record)):
|
|
152
|
+
# Not a finding about the selector: keep it out of the evidence.
|
|
153
|
+
for suffix in ("json", "stdout", "stderr", "rollout", "cli_log"):
|
|
154
|
+
(root / "evidence" / f"{entry['name']}.{suffix}").unlink(missing_ok=True)
|
|
155
|
+
report.update(outcome="unprobeable",
|
|
156
|
+
detail=f"{cli} is not logged in on this host; log in, then re-run")
|
|
157
|
+
if index:
|
|
158
|
+
report["detail"] += f" ({index} earlier probe(s) had already answered)"
|
|
159
|
+
return report
|
|
160
|
+
report["failed"].append(entry["config_id"])
|
|
161
|
+
log(f"{entry['name']} fail {str(record.get('verdict_reason'))[:120]}")
|
|
162
|
+
# With only_missing the rows not re-probed still hold, so a new row that
|
|
163
|
+
# fails is a finding about that row, not about the vendor.
|
|
164
|
+
if not report["passed"] and not only_missing:
|
|
165
|
+
report.update(outcome="failed", detail="no selector of this vendor passed")
|
|
166
|
+
return report
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def main(argv: list[str] | None = None) -> int:
|
|
170
|
+
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
171
|
+
parser.add_argument("--root", type=Path, required=True, help="sweep root to write evidence into")
|
|
172
|
+
parser.add_argument("--vendor", action="append", choices=VENDORS,
|
|
173
|
+
help="vendor to probe; may repeat (default: all four)")
|
|
174
|
+
parser.add_argument("--plan", action="store_true", help="print the commands and probe nothing")
|
|
175
|
+
args = parser.parse_args(argv)
|
|
176
|
+
vendors = args.vendor or list(VENDORS)
|
|
177
|
+
if args.plan:
|
|
178
|
+
for vendor in vendors:
|
|
179
|
+
for entry in plan(vendor):
|
|
180
|
+
print(json.dumps({"name": entry["name"], "argv": command(
|
|
181
|
+
vendor, entry["model"], entry["effort"], "<app-data>")}, ensure_ascii=False))
|
|
182
|
+
return 0
|
|
183
|
+
reports = [sweep(vendor, args.root.expanduser()) for vendor in vendors]
|
|
184
|
+
print(json.dumps(reports, ensure_ascii=False, indent=2))
|
|
185
|
+
return 0 if all(report["outcome"] == "done" for report in reports) else 1
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
if __name__ == "__main__":
|
|
189
|
+
raise SystemExit(main())
|