31ce04c655
Merge the beta-ready Yao Meta Skill architecture, report, evidence gate, and release-boundary updates.\n\nRelease boundary: beta/public testing is allowed; formal world-class, fully reviewed, or superiority claims remain blocked until the pending evidence gates are accepted.
96 lines
3.2 KiB
Python
96 lines
3.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Metadata-only CLI telemetry helpers for yao.py."""
|
|
|
|
import argparse
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
from render_adoption_drift_report import append_event, normalize_event, skill_defaults, utc_now
|
|
|
|
|
|
SCRIPT_INTERFACE = "internal-module"
|
|
SCRIPT_INTERFACE_REASON = "Imported by yao.py to record opt-in metadata-only CLI run telemetry."
|
|
|
|
ENABLE_ENV = "YAO_CLI_TELEMETRY"
|
|
EVENTS_ENV = "YAO_CLI_TELEMETRY_EVENTS"
|
|
TRUTHY = {"1", "true", "yes", "on"}
|
|
FALSY = {"0", "false", "no", "off"}
|
|
|
|
|
|
def add_telemetry_args(parser: argparse.ArgumentParser) -> None:
|
|
parser.add_argument(
|
|
"--record-cli-telemetry",
|
|
action="store_true",
|
|
help="Record metadata-only yao.py command telemetry to reports/telemetry_events.jsonl.",
|
|
)
|
|
parser.add_argument(
|
|
"--no-cli-telemetry",
|
|
action="store_true",
|
|
help="Disable yao.py command telemetry even when YAO_CLI_TELEMETRY is enabled.",
|
|
)
|
|
parser.add_argument(
|
|
"--telemetry-events-jsonl",
|
|
help="Override the local metadata-only telemetry JSONL path.",
|
|
)
|
|
|
|
|
|
def telemetry_enabled(args: argparse.Namespace, environ: dict[str, str] | None = None) -> bool:
|
|
environ = environ or os.environ
|
|
if getattr(args, "no_cli_telemetry", False):
|
|
return False
|
|
if getattr(args, "record_cli_telemetry", False):
|
|
return True
|
|
raw = environ.get(ENABLE_ENV, "").strip().lower()
|
|
if raw in TRUTHY:
|
|
return True
|
|
if raw in FALSY:
|
|
return False
|
|
return False
|
|
|
|
|
|
def telemetry_path(root: Path, args: argparse.Namespace, environ: dict[str, str] | None = None) -> Path:
|
|
environ = environ or os.environ
|
|
configured = getattr(args, "telemetry_events_jsonl", None) or environ.get(EVENTS_ENV)
|
|
if configured:
|
|
return Path(configured).expanduser().resolve()
|
|
return root / "reports" / "telemetry_events.jsonl"
|
|
|
|
|
|
def normalize_command_name(value: Any) -> str:
|
|
raw = str(value or "unknown")
|
|
lowered = raw.strip().lower()
|
|
safe = "".join(char for char in lowered if char.isalnum() or char in {"-", "_"})
|
|
return safe[:64] or "unknown"
|
|
|
|
|
|
def cli_event(root: Path, args: argparse.Namespace, returncode: int) -> dict[str, str]:
|
|
defaults = skill_defaults(root)
|
|
ok = returncode == 0
|
|
return {
|
|
"event": "script_run",
|
|
"skill": defaults["skill"],
|
|
"version": defaults["version"],
|
|
"activation_type": "manual",
|
|
"outcome": "accepted" if ok else "failed",
|
|
"failure_type": "none" if ok else "script_error",
|
|
"timestamp": utc_now(),
|
|
"source": "yao_cli",
|
|
"command": normalize_command_name(getattr(args, "command", "unknown")),
|
|
}
|
|
|
|
|
|
def maybe_record_cli_event(root: Path, args: argparse.Namespace, returncode: int) -> None:
|
|
if not telemetry_enabled(args):
|
|
return
|
|
path = telemetry_path(root, args)
|
|
event, failures = normalize_event(cli_event(root, args, returncode), skill_defaults(root), "yao-cli")
|
|
if failures or event is None:
|
|
sys.stderr.write(f"Telemetry skipped: {'; '.join(failures)}\n")
|
|
return
|
|
try:
|
|
append_event(path, event)
|
|
except OSError as exc:
|
|
sys.stderr.write(f"Telemetry skipped: {exc}\n")
|