← Back to SKILL.md1#!/usr/bin/env python32"""Parse `wrangler deploy --temporary` output into structured JSON.3 4Reads wrangler's stdout/stderr from STDIN and extracts the live workers.dev5URL, the claim URL, the temporary account name/state, the claim window, and6whether a deploy actually happened. Stdlib only — no dependencies.7 8Usage:9 npx wrangler@latest deploy --temporary 2>&1 | python3 parse_deploy_output.py10 python3 parse_deploy_output.py --selftest11"""12 13from __future__ import annotations14 15import json16import re17import sys18 19# Match the live workers.dev URL (subdomain.subdomain.workers.dev).20_LIVE_URL = re.compile(r"https://[A-Za-z0-9._-]+\.workers\.dev\S*")21# Match the claim URL. Cloudflare uses dash.cloudflare.com/claim-preview?claimToken=...22# Keep it broad enough to survive minor path changes while still requiring a claim token.23_CLAIM_URL = re.compile(r"https://\S*claim\S*claimToken=\S+", re.IGNORECASE)24# "Account: Serene Temple (created)" / "Account: example-name (reused)"25# Account names can contain spaces (e.g. "Serene Temple"), so capture everything26# up to the trailing "(state)" marker rather than a single token.27_ACCOUNT = re.compile(28 r"Account:\s*(?P<name>.+?)\s*\((?P<state>created|reused)\)", re.IGNORECASE29)30# "Claim within: 60 minutes"31_CLAIM_WITHIN = re.compile(r"Claim within:\s*(?P<minutes>\d+)\s*minutes?", re.IGNORECASE)32# A successful deploy prints a "Deployed" / "Uploaded" line.33_DEPLOYED = re.compile(r"^\s*(Deployed|Uploaded)\b", re.IGNORECASE | re.MULTILINE)34 35 36def _first(pattern: re.Pattern, text: str) -> str | None:37 m = pattern.search(text)38 if not m:39 return None40 # Strip trailing punctuation that often clings to a URL in log lines.41 return m.group(0).rstrip(".,);]")42 43 44def parse(text: str) -> dict:45 """Extract deploy facts from wrangler output text."""46 account = _ACCOUNT.search(text)47 claim_within = _CLAIM_WITHIN.search(text)48 return {49 "live_url": _first(_LIVE_URL, text),50 "claim_url": _first(_CLAIM_URL, text),51 "account": account.group("name") if account else None,52 "account_state": account.group("state").lower() if account else None,53 "expires_minutes": int(claim_within.group("minutes")) if claim_within else None,54 "deployed": bool(_DEPLOYED.search(text)),55 }56 57 58_SAMPLE = """\59Continuing means you accept Cloudflare's Terms of Service and Privacy Policy.60 61Temporary account ready:62 Account: example-name (created)63 Claim within: 60 minutes64 Claim URL: https://dash.cloudflare.com/claim-preview?claimToken=abc123XYZ65 66Uploaded example-worker67Deployed example-worker triggers68 https://example-worker.example-name.workers.dev69"""70 71_SAMPLE_REUSED = """\72Temporary account ready:73 Account: example-name (reused)74 Claim within: 42 minutes75 Claim URL: https://dash.cloudflare.com/claim-preview?claimToken=def45676Deployed example-worker triggers77 https://example-worker.example-name.workers.dev78"""79 80_SAMPLE_NO_TEMP = """\81✘ [ERROR] You are not logged in.82 83To continue without logging in, rerun this command with `--temporary`.84"""85 86 87def _selftest() -> int:88 r = parse(_SAMPLE)89 assert r["live_url"] == "https://example-worker.example-name.workers.dev", r90 assert r["claim_url"] == "https://dash.cloudflare.com/claim-preview?claimToken=abc123XYZ", r91 assert r["account"] == "example-name", r92 assert r["account_state"] == "created", r93 assert r["expires_minutes"] == 60, r94 assert r["deployed"] is True, r95 96 r2 = parse(_SAMPLE_REUSED)97 assert r2["account_state"] == "reused", r298 assert r2["expires_minutes"] == 42, r299 assert r2["deployed"] is True, r2100 101 r3 = parse(_SAMPLE_NO_TEMP)102 assert r3["live_url"] is None, r3103 assert r3["claim_url"] is None, r3104 assert r3["account"] is None, r3105 assert r3["deployed"] is False, r3106 107 print("selftest: OK")108 return 0109 110 111def main(argv: list[str]) -> int:112 if "--selftest" in argv:113 return _selftest()114 text = sys.stdin.read()115 result = parse(text)116 print(json.dumps(result, indent=2))117 # Non-zero exit if no live URL was found, so callers can branch on it.118 return 0 if result["live_url"] else 1119 120 121if __name__ == "__main__":122 raise SystemExit(main(sys.argv[1:]))123