#!/usr/bin/env bash
# Real demos for P047 "Claude Token Pricing Will Finally Make Sense After This".
# Kettle & Bean (a made-up coffee shop) answers customer chats with Claude Sonnet 5.5 and a support handbook.
#   ask      one request to the shop's assistant, with its bill (tokens in: new / cache write / cache read; out)
#   tokens   counts the tokens in some text, measured from the difference between two requests
#   bill     works out a request's cost at the API's list prices, with and without caching; --month for a month
# Every request goes through Claude Code (headless), signed in with this Mac's Claude plan: no API key is read,
# set or shown (every shell starts from HOME, USER, PATH, LANG, TERM only; PRODUCTION_LESSONS: P042).
# The handbook gets today's "Last updated" line, so its first request finds an empty cache, as a new handbook would.
# Runs on the Mac (it needs the Claude Code login), from ~/token-lab outside this repo (so Claude Code can't read
# our AGENTS.md); commands are typed into one real interactive bash; commands + output go to demo_output.json.
set -euo pipefail
cd "$(dirname "$0")"
LAB="$HOME/token-lab"
rm -rf "$LAB"; mkdir -p "$LAB"
cp -R lab/. "$LAB/"; rm -rf "$LAB/.log"
printf '\nLast updated: %s\n' "$(date '+%Y-%m-%d %H:%M')" >> "$LAB/handbook.md"
trap 'rm -rf "$LAB"' EXIT

python3 - "$LAB" <<'PY'
import fcntl, json, os, pty, re, select, struct, sys, termios, time, subprocess
LAB = sys.argv[1]
READY = re.compile(rb"__READY__:(.*?):__ ")
steps = {}

def clean(text):
    text = re.sub(r"\x1b\[[0-9;?]*[A-Za-z]|\x1b[()][A-Z0-9]", "", text)
    lines = [l.rstrip("\r").split("\r")[-1] for l in text.split("\n")]
    return "\n".join(l.rstrip() for l in lines).strip("\n")

ENV = {k: os.environ[k] for k in ("HOME", "USER", "PATH")}
ENV.update(LANG="en_US.UTF-8", TERM="dumb")

class Shell:
    def __init__(self):
        pid, fd = pty.fork()
        if pid == 0:
            fcntl.ioctl(0, termios.TIOCSWINSZ, struct.pack("HHHH", 40, 100, 0, 0))
            os.chdir(LAB)
            os.execve("/bin/bash", ["bash", "--norc", "--noprofile", "-i"], ENV)
        self.fd, self.where = fd, ""
        os.write(fd, b"stty -echo; PS1='__REA''DY__:\\W:__ '\n")
        self.read()

    def read(self, timeout=900):
        buf, end = b"", time.time() + timeout
        while time.time() < end:
            if select.select([self.fd], [], [], 0.3)[0]:
                buf += os.read(self.fd, 65536)
                m = None
                for m in READY.finditer(buf):
                    pass
                if m:
                    self.where = m.group(1).decode()
                    return clean(buf[:m.start()].decode("utf-8", "replace"))
        raise SystemExit(f"timed out; last output: {buf[-400:]!r}")

    def run(self, key, cmd):
        os.write(self.fd, cmd.encode() + b"\n")
        t = time.time()
        out = self.read()
        assert "Traceback" not in out, out
        steps[key] = {"cmd": cmd, "out": out}
        print(f"--- {key} ({time.time()-t:.0f}s)\n$ {cmd}\n{out}\n", flush=True)
        return out

def last_bill():
    return json.loads(open(os.path.join(LAB, ".log", "ask.jsonl")).read().splitlines()[-1])

s = Shell()
Q = ["Hi, my House Blend bag arrived torn and half the beans spilled. Order KB-20417. Can you help?",
     "A replacement, please. Could you make it Night Owl instead?",
     "Thanks! Also, do you ship to Canada? My sister lives in Toronto.",
     "Great. How do subscriptions work?"]
turns = []
s.run("turn1", f'./ask --chat priya "{Q[0]}"'); turns.append(last_bill())
s.run("tok_words", './tokens "Hello" "Kettle & Bean" "unbelievably" "1234567" "def total(price, qty):"')
s.run("tok_priya", f'./tokens "{Q[0]}"')
s.run("tok_hand", "./tokens --file handbook.md")
s.run("tok_cc", "./tokens --overhead")
for i, q in enumerate(Q[1:], start=2):
    s.run(f"turn{i}", f'./ask --chat priya "{q}"'); turns.append(last_bill())
t2, t4 = turns[1], turns[3]
s.run("bill2", f"./bill sonnet-5.5 {t2['fresh']} {t2['write']} {t2['read']} {t2['out']}")
s.run("bill4", f"./bill sonnet-5.5 {t4['fresh']} {t4['write']} {t4['read']} {t4['out']}")
s.run("bill1", "./bill sonnet-5.5 {fresh} {write} {read} {out}".format(**turns[0]))
s.run("newchat", './ask "Do you ship to Canada?"'); other = last_bill()
t1 = turns[0]
tin1 = t1["fresh"] + t1["write"] + t1["read"]
s.run("month_s", f"./bill --month 6000 sonnet-5.5 {tin1} {t1['out']}")
s.run("month_h", f"./bill --month 6000 haiku-5.5 {tin1} {t1['out']}")
claude_version = subprocess.run(["claude", "--version"], capture_output=True, text=True, env=ENV).stdout.strip()
steps["_meta"] = {"cmd": "", "out": json.dumps({"claude_code": claude_version, "model": "claude-sonnet-5-5",
                   "turns": turns, "newchat": other, "run_at": time.strftime("%Y-%m-%d %H:%M %Z")})}
json.dump(steps, open("demo_output.json", "w"), indent=1, ensure_ascii=False)
print("saved demo_output.json")
PY
