# Clone App Skill Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Build a `/clone-app` Claude Code skill that downloads an Android app's APK from a Google Play URL, reverse engineers it (via the existing `android-reverse-engineering` plugin), analyzes store presence, estimates AI-assisted clone effort + infra cost, produces a market-viability report, and optionally hands off to `writing-plans`. **Architecture:** A new `clone-app` plugin living **inside the fork** of `masa2146/android-reverse-engineering-skill`, alongside the untouched upstream `android-reverse-engineering` plugin. The orchestrator `SKILL.md` drives 8 phases (0–7); deterministic steps (URL parsing, APK download, store scrape, package-name extraction) are factored into small standalone bash/python helper scripts that are unit-testable. The RE plugin's existing scripts are invoked directly by path. AI-judgment phases (stack recommendation, effort estimate, viability verdict) live as prose instructions + reference templates in the skill. **Tech Stack:** Bash (helper scripts + glue), Python 3 (store scrape + JSON parsing where bash is too brittle), Markdown (skill/command/reference docs), `bats` or plain bash assertions for script tests, `curl`, the upstream RE scripts (jadx/Java). ## Global Constraints - Repo root: `/Users/fatih.bulut/PythonWorks/clone_app_skill` (the cloned fork). - Upstream plugin dir `plugins/android-reverse-engineering/` is **NEVER modified** — zero edits, to keep `git pull upstream master` conflict-free. - New plugin dir: `plugins/clone-app/`. - RE scripts are referenced via `${CLAUDE_PLUGIN_ROOT}` of the clone-app plugin, resolving sibling: `"$(dirname "$CLAUDE_PLUGIN_ROOT")/android-reverse-engineering/skills/android-reverse-engineering/scripts"`. - All skill `${CLAUDE_PLUGIN_ROOT}` references use that exact env var (Claude Code sets it per-plugin). - Working dir for runtime artifacts: `./work/{package}/` (relative to user's cwd, NOT inside the plugin). - Package name regex (verbatim): `id=([a-zA-Z0-9._]+)` - APKPure download URL (verbatim): `https://d.apkpure.com/b/APK/{PACKAGE}?version=latest` - "AI Sprint" = one focused Claude Code session (~2-4 hours human review time). Use this unit everywhere; never calendar time. - Bash scripts: `set -euo pipefail` at top, `#!/usr/bin/env bash` shebang. - Python scripts: `#!/usr/bin/env python3`, stdlib only (no pip installs) — use `urllib`, `json`, `re`, `html.parser`. - Report filename (verbatim): `clone-report-YYYY-MM-DD.md` where date is the run date. --- ## File Structure **Plugin scaffold:** - `plugins/clone-app/.claude-plugin/plugin.json` — plugin manifest - `.claude-plugin/marketplace.json` — MODIFY: add clone-app entry (this is the only root-level shared file we touch; low conflict risk) - `plugins/clone-app/skills/clone-app/SKILL.md` — orchestrator, all 8 phases - `plugins/clone-app/commands/clone-app.md` — `/clone-app` slash command **Helper scripts (deterministic, testable):** - `plugins/clone-app/skills/clone-app/scripts/extract-package.sh` — Google Play URL → package name - `plugins/clone-app/skills/clone-app/scripts/download-apk.sh` — APKPure download w/ retries + filetype detect - `plugins/clone-app/skills/clone-app/scripts/resolve-re-scripts.sh` — locate sibling RE scripts dir, fail loud if absent - `plugins/clone-app/skills/clone-app/scripts/scrape-play-store.py` — Google Play page → metrics JSON - `plugins/clone-app/skills/clone-app/scripts/check-appstore.py` — iTunes Search API → iOS presence JSON **Reference docs (AI-judgment guidance):** - `plugins/clone-app/skills/clone-app/references/effort-estimation-guide.md` — how to build the AI-sprint table - `plugins/clone-app/skills/clone-app/references/infra-cost-guide.md` — hosting/db/CDN cost heuristics - `plugins/clone-app/skills/clone-app/references/report-template.md` — the clone-report skeleton - `plugins/clone-app/skills/clone-app/references/stack-recommendation-guide.md` — how to pick/present 2-3 stacks **Tests:** - `plugins/clone-app/tests/test-extract-package.sh` - `plugins/clone-app/tests/test-download-apk.sh` - `plugins/clone-app/tests/test-resolve-re-scripts.sh` - `plugins/clone-app/tests/test-scrape-play-store.py` - `plugins/clone-app/tests/test-check-appstore.py` - `plugins/clone-app/tests/fixtures/` — sample HTML/JSON fixtures - `plugins/clone-app/tests/run-all.sh` — runs every test **Docs:** - `plugins/clone-app/README.md` — install + usage --- ## Task 1: Repo bootstrap + plugin scaffold **Files:** - Verify: `/Users/fatih.bulut/PythonWorks/clone_app_skill/` is the cloned fork with `plugins/android-reverse-engineering/` present - Create: `plugins/clone-app/.claude-plugin/plugin.json` - Modify: `.claude-plugin/marketplace.json` (add clone-app plugin entry) **Interfaces:** - Produces: a valid plugin discoverable by `/plugin install clone-app@android-reverse-engineering-skill`. Plugin name string: `clone-app`. Marketplace name string stays: `android-reverse-engineering-skill`. - [ ] **Step 1: Verify the working dir is the cloned fork** Run: ```bash cd /Users/fatih.bulut/PythonWorks/clone_app_skill && \ ls plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/decompile.sh && \ git remote -v ``` Expected: the `decompile.sh` path lists successfully, and `git remote -v` shows an `origin` pointing at `masa2146/android-reverse-engineering-skill`. If the directory is empty (fork not cloned yet), run: ```bash cd /Users/fatih.bulut/PythonWorks && \ rm -rf clone_app_skill && \ git clone https://github.com/masa2146/android-reverse-engineering-skill.git clone_app_skill && \ cd clone_app_skill && \ git remote add upstream https://github.com/SimoneAvogadro/android-reverse-engineering-skill.git ``` Expected: clone succeeds, upstream remote added. Re-run the verify command above. - [ ] **Step 2: Create the plugin manifest** Create `plugins/clone-app/.claude-plugin/plugin.json`: ```json { "name": "clone-app", "version": "0.1.0", "description": "Analyze a Google Play app: download APK, reverse engineer it, estimate AI-assisted clone effort and infra cost, assess market viability, and optionally generate an implementation plan.", "author": { "name": "masa2146" }, "repository": "https://github.com/masa2146/android-reverse-engineering-skill", "license": "Apache-2.0", "keywords": ["android", "clone", "feasibility", "effort-estimation", "market-analysis", "reverse-engineering"], "skills": "./skills/", "commands": "./commands/" } ``` - [ ] **Step 3: Add clone-app to the marketplace catalog** Read the current `.claude-plugin/marketplace.json`, then append a second object to the `plugins` array (keep the existing `android-reverse-engineering` entry untouched). The `plugins` array becomes: ```json "plugins": [ { "name": "android-reverse-engineering", "source": "./plugins/android-reverse-engineering", "description": "Decompile Android APK/JAR/AAR with jadx, trace call flows through libraries, and document extracted APIs.", "version": "1.5.0", "author": { "name": "Simone Avogadro" }, "repository": "https://github.com/SimoneAvogadro/android-reverse-engineering-skill", "license": "Apache-2.0", "keywords": ["android", "reverse-engineering", "apk", "jadx", "decompile", "api-extraction"], "category": "security" }, { "name": "clone-app", "source": "./plugins/clone-app", "description": "Analyze a Google Play app for cloning: APK reverse engineering, AI-assisted effort estimation, market viability.", "version": "0.1.0", "author": { "name": "masa2146" }, "repository": "https://github.com/masa2146/android-reverse-engineering-skill", "license": "Apache-2.0", "keywords": ["android", "clone", "feasibility", "effort-estimation", "market-analysis"], "category": "security" } ] ``` - [ ] **Step 4: Validate JSON** Run: ```bash cd /Users/fatih.bulut/PythonWorks/clone_app_skill && \ python3 -c "import json; json.load(open('plugins/clone-app/.claude-plugin/plugin.json')); json.load(open('.claude-plugin/marketplace.json')); print('OK')" ``` Expected: `OK` - [ ] **Step 5: Commit** ```bash cd /Users/fatih.bulut/PythonWorks/clone_app_skill && \ git add plugins/clone-app/.claude-plugin/plugin.json .claude-plugin/marketplace.json && \ git commit -m "feat(clone-app): scaffold plugin manifest and marketplace entry" ``` --- ## Task 2: `extract-package.sh` — Google Play URL → package name **Files:** - Create: `plugins/clone-app/skills/clone-app/scripts/extract-package.sh` - Test: `plugins/clone-app/tests/test-extract-package.sh` **Interfaces:** - Produces: `extract-package.sh ` prints the bare package name to stdout, exit 0. On no match, prints nothing to stdout, writes `ERROR: could not extract package` to stderr, exit 1. Accepts either a full Play URL or an already-bare package name (passthrough if it matches `^[a-zA-Z0-9._]+$` with a dot). - [ ] **Step 1: Write the failing test** Create `plugins/clone-app/tests/test-extract-package.sh`: ```bash #!/usr/bin/env bash set -uo pipefail SCRIPT="$(dirname "$0")/../skills/clone-app/scripts/extract-package.sh" fail=0 check() { local desc="$1" expected="$2" actual="$3" if [[ "$expected" == "$actual" ]]; then echo "PASS: $desc" else echo "FAIL: $desc — expected '$expected' got '$actual'"; fail=1 fi } check "full url" "com.example.app" \ "$(bash "$SCRIPT" 'https://play.google.com/store/apps/details?id=com.example.app')" check "url with extra params" "com.whatsapp" \ "$(bash "$SCRIPT" 'https://play.google.com/store/apps/details?id=com.whatsapp&hl=en&gl=US')" check "bare package passthrough" "com.spotify.music" \ "$(bash "$SCRIPT" 'com.spotify.music')" # invalid input → exit 1, empty stdout out="$(bash "$SCRIPT" 'not a url' 2>/dev/null)"; rc=$? check "invalid exit code" "1" "$rc" check "invalid empty stdout" "" "$out" exit $fail ``` - [ ] **Step 2: Run test to verify it fails** Run: ```bash bash /Users/fatih.bulut/PythonWorks/clone_app_skill/plugins/clone-app/tests/test-extract-package.sh ``` Expected: FAIL (script does not exist yet — `bash: ...extract-package.sh: No such file or directory`). - [ ] **Step 3: Write minimal implementation** Create `plugins/clone-app/skills/clone-app/scripts/extract-package.sh`: ```bash #!/usr/bin/env bash set -euo pipefail input="${1:-}" if [[ -z "$input" ]]; then echo "ERROR: usage: extract-package.sh " >&2 exit 1 fi # Case 1: full URL containing id= if [[ "$input" =~ id=([a-zA-Z0-9._]+) ]]; then echo "${BASH_REMATCH[1]}" exit 0 fi # Case 2: already a bare package (must contain a dot, valid chars only) if [[ "$input" =~ ^[a-zA-Z0-9_]+(\.[a-zA-Z0-9_]+)+$ ]]; then echo "$input" exit 0 fi echo "ERROR: could not extract package from '$input'" >&2 exit 1 ``` - [ ] **Step 4: Run test to verify it passes** Run: ```bash chmod +x /Users/fatih.bulut/PythonWorks/clone_app_skill/plugins/clone-app/skills/clone-app/scripts/extract-package.sh && \ bash /Users/fatih.bulut/PythonWorks/clone_app_skill/plugins/clone-app/tests/test-extract-package.sh ``` Expected: all `PASS`, exit 0. - [ ] **Step 5: Commit** ```bash cd /Users/fatih.bulut/PythonWorks/clone_app_skill && \ git add plugins/clone-app/skills/clone-app/scripts/extract-package.sh plugins/clone-app/tests/test-extract-package.sh && \ git commit -m "feat(clone-app): add extract-package.sh URL parser with tests" ``` --- ## Task 3: `resolve-re-scripts.sh` — locate sibling RE scripts dir **Files:** - Create: `plugins/clone-app/skills/clone-app/scripts/resolve-re-scripts.sh` - Test: `plugins/clone-app/tests/test-resolve-re-scripts.sh` **Interfaces:** - Consumes: env var `CLAUDE_PLUGIN_ROOT` (path to the clone-app plugin dir). Falls back to deriving its own location from `$0` if the env var is unset (so it works when run standalone in tests). - Produces: `resolve-re-scripts.sh` prints the absolute path to the RE `scripts/` dir to stdout, exit 0. If that dir doesn't exist, writes a clear error naming the install command to stderr, exit 1. - [ ] **Step 1: Write the failing test** Create `plugins/clone-app/tests/test-resolve-re-scripts.sh`: ```bash #!/usr/bin/env bash set -uo pipefail SCRIPT="$(dirname "$0")/../skills/clone-app/scripts/resolve-re-scripts.sh" fail=0 check() { [[ "$2" == "$3" ]] && echo "PASS: $1" || { echo "FAIL: $1 — expected '$2' got '$3'"; fail=1; }; } # In the real repo layout, the RE scripts dir exists as a sibling plugin. out="$(bash "$SCRIPT" 2>/dev/null)"; rc=$? check "exit 0 when RE present" "0" "$rc" check "ends with scripts dir" "android-reverse-engineering/skills/android-reverse-engineering/scripts" \ "$(basename "$(dirname "$(dirname "$(dirname "$out")")")")/$(basename "$(dirname "$(dirname "$out")")")/$(basename "$(dirname "$out")")/$(basename "$out")" check "decompile.sh exists under resolved dir" "yes" \ "$([[ -f "$out/decompile.sh" ]] && echo yes || echo no)" # When CLAUDE_PLUGIN_ROOT points somewhere with no sibling RE plugin → exit 1 tmp="$(mktemp -d)" out2="$(CLAUDE_PLUGIN_ROOT="$tmp/clone-app" bash "$SCRIPT" 2>/dev/null)"; rc2=$? check "exit 1 when RE missing" "1" "$rc2" rm -rf "$tmp" exit $fail ``` - [ ] **Step 2: Run test to verify it fails** Run: ```bash bash /Users/fatih.bulut/PythonWorks/clone_app_skill/plugins/clone-app/tests/test-resolve-re-scripts.sh ``` Expected: FAIL (script missing). - [ ] **Step 3: Write minimal implementation** Create `plugins/clone-app/skills/clone-app/scripts/resolve-re-scripts.sh`: ```bash #!/usr/bin/env bash set -euo pipefail # Determine this plugin's root. Prefer the env var Claude Code sets; fall back # to deriving from this script's own location (…/clone-app/skills/clone-app/scripts). if [[ -n "${CLAUDE_PLUGIN_ROOT:-}" ]]; then plugin_root="$CLAUDE_PLUGIN_ROOT" else script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # scripts -> clone-app -> skills -> clone-app(plugin root) plugin_root="$(cd "$script_dir/../../.." && pwd)" fi # Sibling RE plugin lives next to clone-app under plugins/ re_scripts="$(cd "$plugin_root/.." 2>/dev/null && pwd)/android-reverse-engineering/skills/android-reverse-engineering/scripts" if [[ ! -d "$re_scripts" ]]; then echo "ERROR: android-reverse-engineering scripts not found at: $re_scripts" >&2 echo "Install it: /plugin install android-reverse-engineering@android-reverse-engineering-skill" >&2 exit 1 fi echo "$re_scripts" ``` - [ ] **Step 4: Run test to verify it passes** Run: ```bash chmod +x /Users/fatih.bulut/PythonWorks/clone_app_skill/plugins/clone-app/skills/clone-app/scripts/resolve-re-scripts.sh && \ bash /Users/fatih.bulut/PythonWorks/clone_app_skill/plugins/clone-app/tests/test-resolve-re-scripts.sh ``` Expected: all `PASS`, exit 0. - [ ] **Step 5: Commit** ```bash cd /Users/fatih.bulut/PythonWorks/clone_app_skill && \ git add plugins/clone-app/skills/clone-app/scripts/resolve-re-scripts.sh plugins/clone-app/tests/test-resolve-re-scripts.sh && \ git commit -m "feat(clone-app): add resolve-re-scripts.sh sibling-plugin locator with tests" ``` --- ## Task 4: `download-apk.sh` — APKPure download with retries + filetype detect **Files:** - Create: `plugins/clone-app/skills/clone-app/scripts/download-apk.sh` - Test: `plugins/clone-app/tests/test-download-apk.sh` **Interfaces:** - Consumes: `download-apk.sh ` and optional env `CLONE_APP_CURL` (override curl binary, used by test to inject a stub). - Produces: downloads to `/app.` where ext is `xapk` or `apk` decided by magic bytes (ZIP `PK\x03\x04` for both; distinguish by presence of `manifest.json` + multiple `.apk` entries → xapk, else apk). Prints the final file path to stdout on success, exit 0. Retries up to 3 times on curl failure. On total failure: stderr message, exit 1. - [ ] **Step 1: Write the failing test** Create `plugins/clone-app/tests/test-download-apk.sh`: ```bash #!/usr/bin/env bash set -uo pipefail SCRIPT="$(dirname "$0")/../skills/clone-app/scripts/download-apk.sh" fail=0 check() { [[ "$2" == "$3" ]] && echo "PASS: $1" || { echo "FAIL: $1 — expected '$2' got '$3'"; fail=1; }; } tmp="$(mktemp -d)" # Stub curl: writes a minimal zip containing manifest.json + two apk entries → xapk cat > "$tmp/fakecurl-xapk.sh" <<'EOF' #!/usr/bin/env bash out=""; prev="" for a in "$@"; do [[ "$prev" == "--output" ]] && out="$a"; prev="$a"; done workdir="$(mktemp -d)" echo '{}' > "$workdir/manifest.json" echo 'a' > "$workdir/base.apk"; echo 'b' > "$workdir/config.apk" ( cd "$workdir" && zip -q -r "$out" . ) exit 0 EOF chmod +x "$tmp/fakecurl-xapk.sh" path="$(CLONE_APP_CURL="$tmp/fakecurl-xapk.sh" bash "$SCRIPT" com.example.app "$tmp/out" 2>/dev/null)"; rc=$? check "xapk exit 0" "0" "$rc" check "xapk extension" "xapk" "${path##*.}" # Stub curl that always fails → exit 1 after retries cat > "$tmp/fakecurl-fail.sh" <<'EOF' #!/usr/bin/env bash exit 22 EOF chmod +x "$tmp/fakecurl-fail.sh" out2="$(CLONE_APP_CURL="$tmp/fakecurl-fail.sh" bash "$SCRIPT" com.example.app "$tmp/out2" 2>/dev/null)"; rc2=$? check "fail exit 1" "1" "$rc2" rm -rf "$tmp" exit $fail ``` - [ ] **Step 2: Run test to verify it fails** Run: ```bash bash /Users/fatih.bulut/PythonWorks/clone_app_skill/plugins/clone-app/tests/test-download-apk.sh ``` Expected: FAIL (script missing). - [ ] **Step 3: Write minimal implementation** Create `plugins/clone-app/skills/clone-app/scripts/download-apk.sh`: ```bash #!/usr/bin/env bash set -euo pipefail package="${1:-}" out_dir="${2:-}" curl_bin="${CLONE_APP_CURL:-curl}" if [[ -z "$package" || -z "$out_dir" ]]; then echo "ERROR: usage: download-apk.sh " >&2 exit 1 fi mkdir -p "$out_dir" tmp_file="$out_dir/app.download" url="https://d.apkpure.com/b/APK/${package}?version=latest" ok=0 for attempt in 1 2 3; do if "$curl_bin" -L --fail "$url" --output "$tmp_file" 2>/dev/null; then ok=1; break fi echo "download attempt $attempt failed, retrying..." >&2 sleep 1 done if [[ "$ok" -ne 1 ]]; then echo "ERROR: failed to download $package after 3 attempts from $url" >&2 rm -f "$tmp_file" exit 1 fi # Decide extension: both APK and XAPK are ZIPs. XAPK = zip containing manifest.json + >=2 .apk entries. ext="apk" if entries="$(unzip -Z1 "$tmp_file" 2>/dev/null)"; then apk_count="$(grep -c '\.apk$' <<<"$entries" || true)" if grep -q '^manifest\.json$' <<<"$entries" && [[ "$apk_count" -ge 1 ]]; then ext="xapk" fi fi final="$out_dir/app.$ext" mv "$tmp_file" "$final" echo "$final" ``` - [ ] **Step 4: Run test to verify it passes** Run: ```bash chmod +x /Users/fatih.bulut/PythonWorks/clone_app_skill/plugins/clone-app/skills/clone-app/scripts/download-apk.sh && \ bash /Users/fatih.bulut/PythonWorks/clone_app_skill/plugins/clone-app/tests/test-download-apk.sh ``` Expected: all `PASS`, exit 0. (Requires `zip`/`unzip` available — standard on macOS.) - [ ] **Step 5: Commit** ```bash cd /Users/fatih.bulut/PythonWorks/clone_app_skill && \ git add plugins/clone-app/skills/clone-app/scripts/download-apk.sh plugins/clone-app/tests/test-download-apk.sh && \ git commit -m "feat(clone-app): add download-apk.sh with retries and xapk/apk detection" ``` --- ## Task 5: `scrape-play-store.py` — Google Play page → metrics JSON **Files:** - Create: `plugins/clone-app/skills/clone-app/scripts/scrape-play-store.py` - Create: `plugins/clone-app/tests/fixtures/play-sample.html` - Test: `plugins/clone-app/tests/test-scrape-play-store.py` **Interfaces:** - Consumes: `scrape-play-store.py ` fetches `https://play.google.com/store/apps/details?id=&hl=en&gl=US`. For testing, `--html-file ` reads local HTML instead of network. - Produces: prints a JSON object to stdout with keys: `package` (str), `title` (str|null), `rating` (float|null), `rating_count` (int|null), `installs` (str|null), `category` (str|null), `developer` (str|null), `updated` (str|null), `source` (str: "google-play"). Missing fields are `null`, never absent. Exit 0 even on partial extraction; exit 1 only on fetch error (network/HTTP) when not using `--html-file`. - [ ] **Step 1: Create the test fixture** Create `plugins/clone-app/tests/fixtures/play-sample.html` — a trimmed but realistic Play page. Include the data-bearing markup the scraper targets: ```html Example App - Apps on Google Play
Updated onJun 1, 2026
1,000,000+Downloads
``` - [ ] **Step 2: Write the failing test** Create `plugins/clone-app/tests/test-scrape-play-store.py`: ```python #!/usr/bin/env python3 import json, subprocess, sys, os HERE = os.path.dirname(os.path.abspath(__file__)) SCRIPT = os.path.join(HERE, "..", "skills", "clone-app", "scripts", "scrape-play-store.py") FIXTURE = os.path.join(HERE, "fixtures", "play-sample.html") def run(): out = subprocess.check_output( [sys.executable, SCRIPT, "com.example.app", "--html-file", FIXTURE]) return json.loads(out) def main(): d = run() fails = [] def check(name, cond): print(f"{'PASS' if cond else 'FAIL'}: {name}") if not cond: fails.append(name) check("package", d["package"] == "com.example.app") check("title", d["title"] == "Example App") check("rating", abs((d["rating"] or 0) - 4.3) < 0.001) check("rating_count", d["rating_count"] == 12873) check("developer", d["developer"] == "Example Studio") check("category", d["category"] == "GAME_PUZZLE") check("installs", d["installs"] == "1,000,000+") check("source", d["source"] == "google-play") # all expected keys present even if null for k in ["package","title","rating","rating_count","installs","category","developer","updated","source"]: check(f"key present: {k}", k in d) sys.exit(1 if fails else 0) main() ``` - [ ] **Step 3: Run test to verify it fails** Run: ```bash python3 /Users/fatih.bulut/PythonWorks/clone_app_skill/plugins/clone-app/tests/test-scrape-play-store.py ``` Expected: FAIL (script missing — `FileNotFoundError` / non-zero exit). - [ ] **Step 4: Write minimal implementation** Create `plugins/clone-app/skills/clone-app/scripts/scrape-play-store.py`: ```python #!/usr/bin/env python3 """Scrape a Google Play store page into a metrics JSON object. Primary source is the embedded ld+json SoftwareApplication block (stable). Falls back to light regex for installs/updated which aren't always in ld+json. """ import sys, json, re, argparse, urllib.request KEYS = ["package", "title", "rating", "rating_count", "installs", "category", "developer", "updated", "source"] def fetch(package): url = f"https://play.google.com/store/apps/details?id={package}&hl=en&gl=US" req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"}) with urllib.request.urlopen(req, timeout=30) as r: return r.read().decode("utf-8", "replace") def parse(html, package): out = {k: None for k in KEYS} out["package"] = package out["source"] = "google-play" # ld+json SoftwareApplication block for m in re.finditer(r'', html, re.DOTALL): try: data = json.loads(m.group(1).strip()) except Exception: continue if isinstance(data, dict) and data.get("@type") == "SoftwareApplication": out["title"] = data.get("name") auth = data.get("author") if isinstance(auth, dict): out["developer"] = auth.get("name") out["category"] = data.get("applicationCategory") ar = data.get("aggregateRating") or {} if ar.get("ratingValue") is not None: try: out["rating"] = float(ar["ratingValue"]) except Exception: pass if ar.get("ratingCount") is not None: try: out["rating_count"] = int(ar["ratingCount"]) except Exception: pass break # installs (e.g. "1,000,000+") m = re.search(r'([\d,]+\+)\s*\s*Downloads', html) if m: out["installs"] = m.group(1) # updated date (e.g. "Updated onJun 1, 2026") m = re.search(r'Updated on\s*([^<]+)', html) if m: out["updated"] = m.group(1).strip() return out def main(): ap = argparse.ArgumentParser() ap.add_argument("package") ap.add_argument("--html-file") args = ap.parse_args() if args.html_file: with open(args.html_file, encoding="utf-8") as f: html = f.read() else: try: html = fetch(args.package) except Exception as e: print(f"ERROR: failed to fetch Play page: {e}", file=sys.stderr) sys.exit(1) print(json.dumps(parse(html, args.package), indent=2)) if __name__ == "__main__": main() ``` - [ ] **Step 5: Run test to verify it passes** Run: ```bash python3 /Users/fatih.bulut/PythonWorks/clone_app_skill/plugins/clone-app/tests/test-scrape-play-store.py ``` Expected: all `PASS`, exit 0. - [ ] **Step 6: Commit** ```bash cd /Users/fatih.bulut/PythonWorks/clone_app_skill && \ git add plugins/clone-app/skills/clone-app/scripts/scrape-play-store.py \ plugins/clone-app/tests/test-scrape-play-store.py \ plugins/clone-app/tests/fixtures/play-sample.html && \ git commit -m "feat(clone-app): add scrape-play-store.py with ld+json parsing and tests" ``` --- ## Task 6: `check-appstore.py` — iOS presence via iTunes Search API **Files:** - Create: `plugins/clone-app/skills/clone-app/scripts/check-appstore.py` - Create: `plugins/clone-app/tests/fixtures/itunes-sample.json` - Test: `plugins/clone-app/tests/test-check-appstore.py` **Interfaces:** - Consumes: `check-appstore.py ` queries `https://itunes.apple.com/search?term=&entity=software&limit=5`. For testing, `--json-file ` reads a local iTunes response instead of network. (Note: there is no Android package → App Store ID mapping; we search by app title/term, best-effort.) - Produces: prints JSON to stdout: `{ "found": bool, "source": "app-store", "results": [ {"name","seller","rating","rating_count","price","url"} ... ] }`. On network error without `--json-file`: still prints `{"found": false, "source":"app-store", "results": [], "error": "..."}` and exit 0 (App Store absence is non-fatal per spec). - [ ] **Step 1: Create the test fixture** Create `plugins/clone-app/tests/fixtures/itunes-sample.json`: ```json { "resultCount": 1, "results": [ { "trackName": "Example App", "sellerName": "Example Studio", "averageUserRating": 4.5, "userRatingCount": 8421, "formattedPrice": "Free", "trackViewUrl": "https://apps.apple.com/app/id123456789" } ] } ``` - [ ] **Step 2: Write the failing test** Create `plugins/clone-app/tests/test-check-appstore.py`: ```python #!/usr/bin/env python3 import json, subprocess, sys, os HERE = os.path.dirname(os.path.abspath(__file__)) SCRIPT = os.path.join(HERE, "..", "skills", "clone-app", "scripts", "check-appstore.py") FIXTURE = os.path.join(HERE, "fixtures", "itunes-sample.json") def main(): out = subprocess.check_output( [sys.executable, SCRIPT, "Example App", "--json-file", FIXTURE]) d = json.loads(out) fails = [] def check(name, cond): print(f"{'PASS' if cond else 'FAIL'}: {name}") if not cond: fails.append(name) check("found true", d["found"] is True) check("source", d["source"] == "app-store") check("one result", len(d["results"]) == 1) r = d["results"][0] check("name", r["name"] == "Example App") check("seller", r["seller"] == "Example Studio") check("rating", abs(r["rating"] - 4.5) < 0.001) check("rating_count", r["rating_count"] == 8421) check("price", r["price"] == "Free") check("url", r["url"].endswith("id123456789")) sys.exit(1 if fails else 0) main() ``` - [ ] **Step 3: Run test to verify it fails** Run: ```bash python3 /Users/fatih.bulut/PythonWorks/clone_app_skill/plugins/clone-app/tests/test-check-appstore.py ``` Expected: FAIL (script missing). - [ ] **Step 4: Write minimal implementation** Create `plugins/clone-app/skills/clone-app/scripts/check-appstore.py`: ```python #!/usr/bin/env python3 """Best-effort check whether an iOS App Store equivalent exists, via the public iTunes Search API. There is no reliable Android-package → App-Store-ID mapping, so we search by term (app title) and return the top matches.""" import sys, json, argparse, urllib.request, urllib.parse def fetch(term): q = urllib.parse.urlencode({"term": term, "entity": "software", "limit": 5}) url = f"https://itunes.apple.com/search?{q}" req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"}) with urllib.request.urlopen(req, timeout=30) as r: return json.loads(r.read().decode("utf-8", "replace")) def shape(data): results = [] for r in data.get("results", []): results.append({ "name": r.get("trackName"), "seller": r.get("sellerName"), "rating": r.get("averageUserRating"), "rating_count": r.get("userRatingCount"), "price": r.get("formattedPrice"), "url": r.get("trackViewUrl"), }) return {"found": len(results) > 0, "source": "app-store", "results": results} def main(): ap = argparse.ArgumentParser() ap.add_argument("term") ap.add_argument("--json-file") args = ap.parse_args() if args.json_file: with open(args.json_file, encoding="utf-8") as f: data = json.load(f) else: try: data = fetch(args.term) except Exception as e: print(json.dumps({"found": False, "source": "app-store", "results": [], "error": str(e)}, indent=2)) sys.exit(0) print(json.dumps(shape(data), indent=2)) if __name__ == "__main__": main() ``` - [ ] **Step 5: Run test to verify it passes** Run: ```bash python3 /Users/fatih.bulut/PythonWorks/clone_app_skill/plugins/clone-app/tests/test-check-appstore.py ``` Expected: all `PASS`, exit 0. - [ ] **Step 6: Commit** ```bash cd /Users/fatih.bulut/PythonWorks/clone_app_skill && \ git add plugins/clone-app/skills/clone-app/scripts/check-appstore.py \ plugins/clone-app/tests/test-check-appstore.py \ plugins/clone-app/tests/fixtures/itunes-sample.json && \ git commit -m "feat(clone-app): add check-appstore.py iTunes search with tests" ``` --- ## Task 7: Test runner aggregator **Files:** - Create: `plugins/clone-app/tests/run-all.sh` **Interfaces:** - Produces: `run-all.sh` runs every test (bash + python), prints a summary, exits non-zero if any fail. - [ ] **Step 1: Write the runner** Create `plugins/clone-app/tests/run-all.sh`: ```bash #!/usr/bin/env bash set -uo pipefail HERE="$(cd "$(dirname "$0")" && pwd)" fail=0 echo "=== bash tests ===" for t in "$HERE"/test-*.sh; do echo "--- $(basename "$t") ---" bash "$t" || fail=1 done echo "=== python tests ===" for t in "$HERE"/test-*.py; do echo "--- $(basename "$t") ---" python3 "$t" || fail=1 done echo if [[ "$fail" -eq 0 ]]; then echo "ALL TESTS PASSED"; else echo "SOME TESTS FAILED"; fi exit $fail ``` - [ ] **Step 2: Run it** Run: ```bash chmod +x /Users/fatih.bulut/PythonWorks/clone_app_skill/plugins/clone-app/tests/run-all.sh && \ bash /Users/fatih.bulut/PythonWorks/clone_app_skill/plugins/clone-app/tests/run-all.sh ``` Expected: `ALL TESTS PASSED`, exit 0 (all of Tasks 2–6 green). - [ ] **Step 3: Commit** ```bash cd /Users/fatih.bulut/PythonWorks/clone_app_skill && \ git add plugins/clone-app/tests/run-all.sh && \ git commit -m "test(clone-app): add aggregate test runner" ``` --- ## Task 8: Reference docs — effort, infra cost, stack, report template **Files:** - Create: `plugins/clone-app/skills/clone-app/references/stack-recommendation-guide.md` - Create: `plugins/clone-app/skills/clone-app/references/effort-estimation-guide.md` - Create: `plugins/clone-app/skills/clone-app/references/infra-cost-guide.md` - Create: `plugins/clone-app/skills/clone-app/references/report-template.md` **Interfaces:** - Produces: four reference docs the SKILL.md links into during Phases 4–6. No code; these are the judgment rubrics that keep AI output consistent. - [ ] **Step 1: Write the stack recommendation guide** Create `plugins/clone-app/skills/clone-app/references/stack-recommendation-guide.md`: ```markdown # Stack Recommendation Guide (Phase 4) Goal: present the user 2-3 concrete stack options for building the clone, then let them pick. The pick locks effort + cost math in Phase 5. ## Inputs you have - Detected original framework (from RE fingerprint): Native Kotlin/Java, Flutter, React Native, etc. - Detected HTTP stack + backend signals (Retrofit/Ktor/Apollo/GraphQL/WebSocket). - Feature surface (screen count, SDKs, permissions). ## How to choose the 2-3 options Always include: 1. **Fastest for AI-assisted dev** — default to **Flutter** (single codebase, strong AI codegen, fast UI) unless the app is heavily native-platform-dependent. 2. **JS-ecosystem option** — **React Native + Expo** when the team is JS-leaning or web reuse matters. 3. **Match-the-original** — only when the original's nativeness is essential (deep platform APIs, AR, heavy native SDKs). Note the higher effort. ## Backend - If RE shows first-party API hosts → a backend is required. Recommend **Node/TS (NestJS or Express)** or **Supabase** (fastest with AI) unless GraphQL detected → recommend **Apollo Server** or **Hasura**. - If only third-party hosts (Firebase, payment SDKs) → likely **BaaS / no custom backend**; note it. ## Output format to the user Present a short table: Option | Mobile stack | Backend | Why | Relative effort (Low/Med/High). Then ask: "Which stack should I base the effort + cost estimate on?" ``` - [ ] **Step 2: Write the effort estimation guide** Create `plugins/clone-app/skills/clone-app/references/effort-estimation-guide.md`: ```markdown # Effort Estimation Guide (Phase 5) — AI-Assisted Units Estimate in **AI Sprints**, NOT human days. 1 AI Sprint = one focused Claude Code session producing a reviewable increment (~2-4h human review time). ## Method 1. Build the feature list from RE output: - Screens = Activity + Fragment count (dedupe obvious base classes). - API surface = endpoint count from find-api-calls. - Integrations = third-party SDKs (auth, payment, maps, analytics, push, chat). - Backend = REST/GraphQL/WebSocket presence + first-party host count. 2. Assign each feature a complexity and sprint range using the table below. 3. Sum to a range (min–max sprints). Never give a single false-precise number. ## Reference sprint costs | Feature class | Low | Typical | High | Notes | |---|---|---|---|---| | Project scaffold + CI | 0.5 | 1 | 1 | nav, theming, state mgmt setup | | Auth (email/social) | 1 | 1.5 | 2 | +1 if custom backend auth | | Simple list/detail screen | 0.3 | 0.5 | 1 | per screen, AI-fast | | Complex interactive screen | 1 | 2 | 3 | maps, editors, realtime | | API integration layer | 1 | 2 | 3 | scales with endpoint count | | Each major SDK integration | 0.5 | 1 | 2 | payment > maps > analytics | | Custom backend (CRUD) | 2 | 4 | 8 | scales with entity + endpoint count | | Realtime (WebSocket/push) | 1 | 2 | 4 | | | Offline/sync | 2 | 3 | 5 | | | Polish/QA/store submission | 1 | 2 | 3 | | ## Obfuscation caveat If RE flagged heavy R8/Flutter (feature list incomplete), add a **+20-40% uncertainty band** and state it explicitly in the report. ## Output A table: Category | Complexity | Sprints (min–max), then a TOTAL row. ``` - [ ] **Step 3: Write the infra cost guide** Create `plugins/clone-app/skills/clone-app/references/infra-cost-guide.md`: ```markdown # Infrastructure Cost Guide (Phase 5) Estimate **monthly USD** at three scales: MVP (<1k MAU), Growth (~50k MAU), Scale (~500k MAU). Use round heuristics; mark assumptions. ## Components | Component | MVP | Growth | Scale | Notes | |---|---|---|---|---| | App hosting/backend | $0-20 | $50-200 | $500-2k | Railway/Render/Fly → AWS/GCP | | Managed DB (Postgres) | $0-15 | $50-150 | $300-1k | Supabase/Neon/RDS | | Object storage/CDN | $0-5 | $20-80 | $200-800 | S3+CloudFront/Cloudflare | | Auth (managed) | $0 | $0-100 | $200-500 | Supabase/Auth0 tiers | | Push notifications | $0 | $0-50 | $50-300 | FCM free; OneSignal paid tiers | | Third-party APIs | varies | varies | varies | maps, SMS, payments % | | Monitoring | $0 | $20-50 | $100-300 | Sentry/Datadog | ## Third-party cost flags from RE - Maps SDK → Google Maps billing after free tier. - Payment SDK → % per transaction (Stripe ~2.9%+30¢). - SMS/OTP → per-message (Twilio). List each detected paid dependency explicitly. ## Output A 3-column (MVP/Growth/Scale) monthly cost table + a one-line "biggest cost driver". ``` - [ ] **Step 4: Write the report template** Create `plugins/clone-app/skills/clone-app/references/report-template.md`: ```markdown # Clone Feasibility Report — {APP_TITLE} **Package:** {PACKAGE} **Date:** {DATE} **Analyzed by:** clone-app skill ## 1. App Overview - Title / developer / category / installs / rating ({RATING} from {RATING_COUNT} reviews) - iOS App Store presence: {YES/NO + link} - One-paragraph description of what the app does. ## 2. Tech Stack (Detected) - Mobile framework: {framework} (RE fingerprint marker: {marker}) - HTTP stack: {Retrofit/Ktor/...} - Backend signals: {first-party hosts, REST/GraphQL/WS} - Notable SDKs: {list} - Obfuscation level: {low/med/high} — analysis completeness caveat if high. ## 3. Recommended Clone Stack - Selected by user: {stack} - Rationale: {1-2 lines} ## 4. Feature List (from APK) - Screens: {n} - API endpoints: {n} (key ones listed) - Integrations: {list} - Backend required: {yes/no + why} ## 5. Effort Estimate (AI-Assisted) {effort table from effort-estimation-guide} **Total: {min}–{max} AI Sprints** (1 sprint ≈ one focused Claude Code session). Uncertainty band: {±%} due to {reason}. ## 6. Infrastructure Cost Estimate (monthly) {MVP/Growth/Scale table from infra-cost-guide} Biggest cost driver: {item}. ## 7. Market Analysis - Current app metrics: installs {x}, rating {y}, review velocity {if known}. - Competitor landscape: {2-4 named competitors}. - Target market size: {rough estimate + basis}. - Differentiation opportunities: {list}. ## 8. Viability Verdict **{GO / CONDITIONAL GO / NO GO}** - Key risks: {list} - Key opportunities: {list} - Recommendation rationale: {2-3 sentences tying effort+cost vs market}. ## 9. Next Step {Link to implementation plan if user proceeds, else "report only".} ``` - [ ] **Step 5: Commit** ```bash cd /Users/fatih.bulut/PythonWorks/clone_app_skill && \ git add plugins/clone-app/skills/clone-app/references/ && \ git commit -m "docs(clone-app): add stack/effort/infra/report reference guides" ``` --- ## Task 9: Orchestrator SKILL.md — all 8 phases **Files:** - Create: `plugins/clone-app/skills/clone-app/SKILL.md` **Interfaces:** - Consumes: all helper scripts (Tasks 2-6), the RE script dir (Task 3 resolver), and reference docs (Task 8). Uses `${CLAUDE_PLUGIN_ROOT}` for its own scripts. - Produces: the activatable skill that runs the full Phase 0-7 workflow. Trigger phrases + frontmatter so Claude Code auto-loads it. - [ ] **Step 1: Write SKILL.md** Create `plugins/clone-app/skills/clone-app/SKILL.md`: ```markdown --- description: Analyze a Google Play app to assess cloning it — download the APK, reverse engineer the tech stack and APIs, analyze app-store presence, estimate AI-assisted build effort and infrastructure cost, judge market viability, and optionally generate an implementation plan. Use when the user gives a Google Play URL or package name and wants a clone feasibility analysis, effort estimate, or tech-stack breakdown. 中文触发词:克隆应用、复刻这个app、分析可行性、估算开发量、克隆可行性分析 trigger: clone app|clone this app|clone feasibility|feasibility analysis|estimate effort to build|reverse engineer and clone|analyze this play store app|can I clone|克隆应用|复刻|可行性分析 --- # Clone App — Feasibility & Effort Analysis Take a Google Play URL (or package name), reverse engineer the app, analyze its market, estimate AI-assisted clone effort and infrastructure cost, and produce a viability report. If the user approves, hand off to the writing-plans skill to generate a full implementation plan. This skill orchestrates 8 phases. Deterministic steps are factored into helper scripts under `${CLAUDE_PLUGIN_ROOT}/skills/clone-app/scripts/`. Reverse engineering reuses the sibling `android-reverse-engineering` plugin's scripts. ## Legal note Only analyze apps you are authorized to (your own, or for lawful interoperability / research). Surface this to the user if intent is unclear. Do not proceed for clearly infringing intent. ## Phase 0: Input & Validation Extract the package name: ```bash PKG="$(bash ${CLAUDE_PLUGIN_ROOT}/skills/clone-app/scripts/extract-package.sh "")" ``` If it exits non-zero, ask the user for the package name directly, then re-run. Create the working dir: `WORK="./work/$PKG"` and `mkdir -p "$WORK"`. ## Phase 1: APK Download ```bash APK="$(bash ${CLAUDE_PLUGIN_ROOT}/skills/clone-app/scripts/download-apk.sh "$PKG" "$WORK")" ``` The script retries 3× and prints the path (`app.apk` or `app.xapk`). If it exits non-zero, tell the user the download failed and ask for a local APK/XAPK path; set `APK` to that path. ## Phase 2: Reverse Engineering Resolve the sibling RE scripts: ```bash RE="$(bash ${CLAUDE_PLUGIN_ROOT}/skills/clone-app/scripts/resolve-re-scripts.sh)" ``` If it exits non-zero, show its error (RE plugin not installed) and stop. Run, in order, reading each output before the next: 1. `bash "$RE/fingerprint.sh" "$APK"` — framework, HTTP stack, obfuscation, SDKs, native libs. - **If framework is Flutter / React Native / Cordova / Xamarin:** tell the user Java decompilation is limited; proceed but rely on manifest + strings + hardcoded URLs + the fingerprint SDK list. Skip steps 3-5's deep API extraction expectations. 2. `bash "$RE/check-deps.sh"` — parse `INSTALL_REQUIRED:` / `INSTALL_OPTIONAL:` lines. Install required deps with `bash "$RE/install-dep.sh" `; re-run check-deps until clean. Ask the user before installing optional deps (vineflower, dex2jar). 3. `bash "$RE/decompile.sh" "$APK"` (add `--deobf` if fingerprint showed heavy obfuscation). Output lands under the RE script's `output/` — note the `sources/` path it prints. 4. If the app is Kotlin: `bash "$RE/recover-kotlin-names.sh" "$WORK/output/names/"`. 5. `bash "$RE/find-api-calls.sh" ` (full scan; add `--ktor`/`--apollo`/`--paths` as the fingerprint suggests). From these outputs assemble: framework, HTTP stack, **API endpoint list**, first-party vs third-party hosts, AndroidManifest summary (permissions, components), and a **feature list** (screen count, SDKs, backend signals). Keep this in context for later phases. ## Phase 3: Store Analysis ```bash python3 ${CLAUDE_PLUGIN_ROOT}/skills/clone-app/scripts/scrape-play-store.py "$PKG" > "$WORK/play.json" ``` Read `play.json` for rating, rating_count, installs, category, developer, updated. Use the `title` to check iOS: ```bash python3 ${CLAUDE_PLUGIN_ROOT}/skills/clone-app/scripts/check-appstore.py "" > "$WORK/appstore.json" ``` If Play scrape returned mostly nulls (page layout changed), fall back to a web search for the app's metrics and note the source. App Store absence is fine — continue with Google Play data only. ## Phase 4: Stack Recommendation Read `${CLAUDE_PLUGIN_ROOT}/skills/clone-app/references/stack-recommendation-guide.md`. Using the RE results + store data, present 2-3 stack options as a table and ask the user to choose. **Wait for the user's choice before Phase 5.** Lock it. ## Phase 5: Effort & Cost Estimation Read `${CLAUDE_PLUGIN_ROOT}/skills/clone-app/references/effort-estimation-guide.md` and `infra-cost-guide.md`. Build: - the feature list → AI-Sprint effort table (min-max total, uncertainty band), - the MVP/Growth/Scale monthly infra cost table. Base both on the **user-selected stack** from Phase 4. ## Phase 6: Market Viability Report Read `${CLAUDE_PLUGIN_ROOT}/skills/clone-app/references/report-template.md`. Fill every section from the data gathered. For market analysis (competitors, market size), use web search as needed. Produce a GO / CONDITIONAL GO / NO GO verdict tying effort + cost against market opportunity. Write the report: ``` $WORK/clone-report-<YYYY-MM-DD>.md ``` (Use the actual run date.) Show the user a concise summary + the verdict. ## Phase 7: Decision Gate Ask: "Report saved to `$WORK/clone-report-<date>.md`. Proceed to build the implementation plan?" - **Yes** → invoke the `superpowers:writing-plans` skill, passing the report as context (the selected stack, feature list, and effort table become the plan's spec). - **No** → stop; the report stands on its own. ## Error Handling Summary | Scenario | Action | |---|---| | Package not in URL | ask user for package name | | Download fails 3× | ask for local APK path | | RE plugin missing | show resolver error, stop | | Flutter/RN/Cordova/Xamarin | warn, continue with limited RE | | App Store not found | continue Google Play only | | Play scrape returns nulls | web-search fallback, note source | | Heavy obfuscation | add uncertainty band, note in report | | writing-plans unavailable | write the plan as Markdown manually | ``` - [ ] **Step 2: Validate frontmatter + links** Run: ```bash cd /Users/fatih.bulut/PythonWorks/clone_app_skill && \ python3 - <<'EOF' import re, sys, os p = "plugins/clone-app/skills/clone-app/SKILL.md" s = open(p, encoding="utf-8").read() assert s.startswith("---"), "missing frontmatter" fm = s.split("---",2)[1] assert "description:" in fm and "trigger:" in fm, "frontmatter keys missing" # every referenced script/reference path under the plugin must exist base = "plugins/clone-app/skills/clone-app" for rel in ["scripts/extract-package.sh","scripts/download-apk.sh", "scripts/resolve-re-scripts.sh","scripts/scrape-play-store.py", "scripts/check-appstore.py","references/stack-recommendation-guide.md", "references/effort-estimation-guide.md","references/infra-cost-guide.md", "references/report-template.md"]: assert os.path.isfile(os.path.join(base, rel)), f"missing {rel}" print("OK") EOF ``` Expected: `OK` - [ ] **Step 3: Commit** ```bash cd /Users/fatih.bulut/PythonWorks/clone_app_skill && \ git add plugins/clone-app/skills/clone-app/SKILL.md && \ git commit -m "feat(clone-app): add orchestrator SKILL.md (phases 0-7)" ``` --- ## Task 10: `/clone-app` slash command + README **Files:** - Create: `plugins/clone-app/commands/clone-app.md` - Create: `plugins/clone-app/README.md` **Interfaces:** - Consumes: SKILL.md (Task 9). - Produces: the user-invocable `/clone-app <url>` command and install/usage docs. - [ ] **Step 1: Write the command file** Create `plugins/clone-app/commands/clone-app.md`: ```markdown --- allowed-tools: Bash, Read, Glob, Grep, Write, Edit, WebFetch, WebSearch, Skill description: Analyze a Google Play app for cloning — RE, effort, market viability, optional plan user-invocable: true argument-hint: <Google Play URL or package name> argument: Google Play URL or package name (optional) --- # /clone-app Run the full clone-feasibility workflow on a Google Play app. ## Instructions Follow the clone-app skill workflow in `${CLAUDE_PLUGIN_ROOT}/skills/clone-app/SKILL.md` exactly, phases 0 through 7. ### Step 1: Get the target If the user passed a URL or package name as an argument, use it. Otherwise ask for the Google Play URL or package name. ### Step 2: Run the skill Execute Phase 0 → Phase 7 from SKILL.md. Pause for the user at: - Phase 4 (stack choice), - Phase 7 (proceed to implementation plan?). Honor the Error Handling Summary table in SKILL.md at every phase. ### Step 3: Deliver Ensure the report is written to `./work/<package>/clone-report-<date>.md` and summarize the verdict. If the user approves at Phase 7, invoke `superpowers:writing-plans` with the report as the spec. ``` - [ ] **Step 2: Write the README** Create `plugins/clone-app/README.md`: ```markdown # clone-app — Clone Feasibility Analyzer (Claude Code skill) Give it a Google Play URL. It downloads the APK, reverse engineers the tech stack and APIs (via the sibling `android-reverse-engineering` plugin), analyzes the app's store presence, estimates **AI-assisted** build effort (in AI Sprints) and monthly infrastructure cost, judges market viability (GO / CONDITIONAL GO / NO GO), and — if you approve — generates a full implementation plan. ## Requirements - The `android-reverse-engineering` plugin (ships in this same repo). - Java JDK 17+ and jadx (the RE plugin auto-installs jadx if missing). - `curl`, Python 3 (stdlib only), `unzip`. ## Install ```text /plugin marketplace add /path/to/this/repo /plugin install android-reverse-engineering@android-reverse-engineering-skill /plugin install clone-app@android-reverse-engineering-skill ``` ## Usage ```text /clone-app https://play.google.com/store/apps/details?id=com.example.app ``` Or natural language: "Analyze this Play Store app for cloning: <url>". The skill pauses twice for your input: choosing the clone stack, and deciding whether to generate the implementation plan. ## Output ``` ./work/<package>/ ├── app.apk | app.xapk ├── output/ # decompiled sources + Kotlin name maps ├── play.json # store metrics ├── appstore.json # iOS presence └── clone-report-YYYY-MM-DD.md ``` ## Keeping the RE plugin up to date This repo is a fork. To pull upstream improvements: ```bash git remote add upstream https://github.com/SimoneAvogadro/android-reverse-engineering-skill.git git pull upstream master ``` The clone-app plugin lives in its own directory, so upstream updates to `android-reverse-engineering` merge cleanly. ## Legal For lawful use only — your own apps, authorized interoperability, security research, or education. You are responsible for compliance. ``` - [ ] **Step 3: Validate command frontmatter** Run: ```bash cd /Users/fatih.bulut/PythonWorks/clone_app_skill && \ python3 -c " s=open('plugins/clone-app/commands/clone-app.md',encoding='utf-8').read() assert s.startswith('---') and 'user-invocable: true' in s and 'allowed-tools:' in s print('OK')" ``` Expected: `OK` - [ ] **Step 4: Commit** ```bash cd /Users/fatih.bulut/PythonWorks/clone_app_skill && \ git add plugins/clone-app/commands/clone-app.md plugins/clone-app/README.md && \ git commit -m "feat(clone-app): add /clone-app command and README" ``` --- ## Task 11: End-to-end smoke test + final verification **Files:** - Create: `plugins/clone-app/tests/smoke-structure.sh` **Interfaces:** - Produces: a structural smoke test verifying the whole plugin is wired correctly (all files present, all scripts executable, JSON valid, full test suite green). No network — this validates the package, not a live download. - [ ] **Step 1: Write the smoke test** Create `plugins/clone-app/tests/smoke-structure.sh`: ```bash #!/usr/bin/env bash set -uo pipefail ROOT="$(cd "$(dirname "$0")/../../.." && pwd)" # repo root P="$ROOT/plugins/clone-app" fail=0 must_exist() { [[ -e "$1" ]] && echo "PASS exists: ${1#$ROOT/}" || { echo "FAIL missing: ${1#$ROOT/}"; fail=1; }; } must_exec() { [[ -x "$1" ]] && echo "PASS exec: ${1#$ROOT/}" || { echo "FAIL not exec: ${1#$ROOT/}"; fail=1; }; } must_exist "$P/.claude-plugin/plugin.json" must_exist "$P/skills/clone-app/SKILL.md" must_exist "$P/commands/clone-app.md" must_exist "$P/README.md" for s in extract-package.sh download-apk.sh resolve-re-scripts.sh; do must_exist "$P/skills/clone-app/scripts/$s"; must_exec "$P/skills/clone-app/scripts/$s" done for s in scrape-play-store.py check-appstore.py; do must_exist "$P/skills/clone-app/scripts/$s" done for r in stack-recommendation-guide effort-estimation-guide infra-cost-guide report-template; do must_exist "$P/skills/clone-app/references/$r.md" done # JSON validity python3 -c "import json;json.load(open('$P/.claude-plugin/plugin.json'));json.load(open('$ROOT/.claude-plugin/marketplace.json'))" \ && echo "PASS json valid" || { echo "FAIL json invalid"; fail=1; } # clone-app present in marketplace python3 -c " import json;d=json.load(open('$ROOT/.claude-plugin/marketplace.json')) names=[p['name'] for p in d['plugins']] assert 'clone-app' in names and 'android-reverse-engineering' in names print('PASS marketplace has both plugins')" || { echo "FAIL marketplace entries"; fail=1; } exit $fail ``` - [ ] **Step 2: Run smoke + full suite** Run: ```bash chmod +x /Users/fatih.bulut/PythonWorks/clone_app_skill/plugins/clone-app/tests/smoke-structure.sh && \ bash /Users/fatih.bulut/PythonWorks/clone_app_skill/plugins/clone-app/tests/smoke-structure.sh && \ bash /Users/fatih.bulut/PythonWorks/clone_app_skill/plugins/clone-app/tests/run-all.sh ``` Expected: smoke test all `PASS`; `ALL TESTS PASSED`. Both exit 0. - [ ] **Step 3: Verify upstream plugin untouched** Run: ```bash cd /Users/fatih.bulut/PythonWorks/clone_app_skill && \ git status --porcelain plugins/android-reverse-engineering/ && \ echo "---" && \ git log --oneline -1 ``` Expected: the `git status` line for `plugins/android-reverse-engineering/` is **empty** (no modifications to upstream). The `---` separator prints, then the last commit shows. - [ ] **Step 4: Commit** ```bash cd /Users/fatih.bulut/PythonWorks/clone_app_skill && \ git add plugins/clone-app/tests/smoke-structure.sh && \ git commit -m "test(clone-app): add structural smoke test" ``` - [ ] **Step 5: Final manual checklist (report to user, do not automate)** Confirm and report: - [ ] `git pull upstream master` strategy documented in README (Task 10) ✓ - [ ] Upstream `plugins/android-reverse-engineering/` has zero diffs (Step 3) ✓ - [ ] All scripts tested green (Step 2) ✓ - [ ] Skill triggers + command are wired (Tasks 9-10) ✓ - [ ] Recommend the user do ONE live run against a known small app to validate the network paths (APKPure download + Play scrape), since those aren't covered by offline tests. Suggest: pick a small free app, run `/clone-app <url>`, stop after Phase 3 to confirm download + store JSON look right. --- ## Self-Review Notes **Spec coverage check:** - Phase 0-7 → Task 9 SKILL.md ✓ (all phases present, in order) - Repo structure / upstream-untouched → Task 1 + Task 11 Step 3 verification ✓ - APK download w/ retries + xapk detect → Task 4 ✓ - RE script invocation via sibling path → Task 3 resolver + Task 9 Phase 2 ✓ - Store analysis (Play + App Store) → Tasks 5, 6 + Phase 3 ✓ - Stack recommendation (Option C + user choice) → Task 8 guide + Phase 4 ✓ - Effort estimation in AI Sprints → Task 8 guide + Phase 5 ✓ - Infra cost → Task 8 guide + Phase 5 ✓ - Market viability report + GO/NO-GO → Task 8 template + Phase 6 ✓ - Decision gate → writing-plans handoff → Phase 7 ✓ - All error-handling rows → Phase 2/3 + SKILL.md error table ✓ - Known limitations (iOS, obfuscation, install ranges) → reflected in guides/template ✓ - Install instructions → Task 10 README ✓ **Placeholder scan:** No TBD/TODO; all code blocks complete; report-template uses intentional `{PLACEHOLDER}` tokens that are fill-in fields for runtime, not plan gaps. **Type/name consistency:** Script names, JSON keys (`package/title/rating/rating_count/ installs/category/developer/updated/source`; `found/source/results/name/seller/rating/ rating_count/price/url`), and env vars (`CLAUDE_PLUGIN_ROOT`, `CLONE_APP_CURL`) match across tasks. `$WORK`, `$PKG`, `$APK`, `$RE` consistent in SKILL.md. ```