Files
claude-video/tests/test_setup.py
T
bradautomates 429f3143e5 Restructure as a self-contained Agent Skills package (fix Codex install)
Move the skill into skills/watch/ so SKILL.md and its scripts/ runtime are
siblings inside one folder. `npx skills add` (Codex/Cursor/Copilot/agents) now
copies a working skill as a unit; previously it grabbed the root SKILL.md alone
and left scripts/ behind, so the skill was dead on arrival on every non-Claude
host. Mirrors the layout last30days-skill adopted for the same reason.

- skills/watch/{SKILL.md,scripts/}: self-contained skill folder
- SKILL.md: resolve a harness-agnostic $SKILL_DIR (the dir it was Read from)
  instead of the Claude-Code-only ${CLAUDE_SKILL_DIR}; guard + 19 call sites
- drop commands/watch.md: /watch derives from frontmatter (name + user-invocable)
- .codex-plugin/plugin.json: full manifest with "skills": "./skills/" + interface
- add .agents/plugins/marketplace.json, AGENTS.md, CLAUDE.md, .skillignore
- build-skill.sh: archive the skills/watch subtree (one SKILL.md, no zip -d)
- fix paths in tests, hooks hint, .gitattributes, release.yml
- relocate dev-sync.sh to repo root and fix REPO_ROOT
- README: content-ideas structure, npx skills install, star history

Verified: 37/37 tests pass; npx skills add bundles the full scripts/ runtime;
manifests valid; versions synced at 0.1.3.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 22:12:54 +10:00

81 lines
2.7 KiB
Python

"""setup.py --json surfaces the resolved watch detail."""
from __future__ import annotations
import json
import os
import subprocess
import sys
from pathlib import Path
SETUP = Path(__file__).resolve().parent.parent / "skills" / "watch" / "scripts" / "setup.py"
def _run(args, *, home=None, extra_env=None):
env = dict(os.environ)
env.pop("WATCH_DETAIL", None)
# Don't let a real key in the developer's shell env leak into the test.
env.pop("GROQ_API_KEY", None)
env.pop("OPENAI_API_KEY", None)
env.pop("SETUP_COMPLETE", None)
if home is not None:
env["HOME"] = str(home)
env["USERPROFILE"] = str(home) # Windows
if extra_env:
env.update(extra_env)
return subprocess.run(
[sys.executable, str(SETUP), *args],
capture_output=True, text=True, env=env,
)
def _write_env(home: Path, body: str) -> None:
cfg = home / ".config" / "watch"
cfg.mkdir(parents=True, exist_ok=True)
f = cfg / ".env"
f.write_text(body, encoding="utf-8")
f.chmod(0o600)
def test_json_reports_watch_detail():
proc = _run(["--json"])
assert proc.returncode == 0, proc.stderr
data = json.loads(proc.stdout)
assert data["watch_detail"] == "balanced"
def test_keyless_completed_setup_proceeds_silently(tmp_path):
"""A user who finished setup without a key must NOT be nagged forever."""
_write_env(tmp_path, "GROQ_API_KEY=\nOPENAI_API_KEY=\nSETUP_COMPLETE=true\n")
chk = _run(["--check"], home=tmp_path)
assert chk.returncode == 0, f"keyless-complete should pass --check; got {chk.returncode}: {chk.stderr}"
assert chk.stdout == "" and chk.stderr == ""
js = json.loads(_run(["--json"], home=tmp_path).stdout)
assert js["can_proceed"] is True
assert js["first_run"] is False
assert js["setup_complete"] is True
# status still encourages a key even though we can proceed
assert js["status"] == "needs_key"
def test_keyless_first_run_is_encouraged(tmp_path):
"""Genuine first run with no key: --check reports exit 3 (encourage a key)."""
_write_env(tmp_path, "GROQ_API_KEY=\nOPENAI_API_KEY=\n")
chk = _run(["--check"], home=tmp_path)
assert chk.returncode == 3, chk.stderr
js = json.loads(_run(["--json"], home=tmp_path).stdout)
assert js["can_proceed"] is False
assert js["first_run"] is True
def test_key_present_is_ready(tmp_path):
_write_env(tmp_path, "GROQ_API_KEY=sk-test-abc\n")
chk = _run(["--check"], home=tmp_path)
assert chk.returncode == 0, chk.stderr
js = json.loads(_run(["--json"], home=tmp_path).stdout)
assert js["status"] == "ready"
assert js["can_proceed"] is True
assert js["whisper_backend"] == "groq"