Skill: horngtan/add-tiffin-order-roty-input (version 0.1.0)

name: add-tiffin-order-roty-input description: "POST-only: Parse 'Roty input' messages and create Roty orders via HTTPS POST (no Playwright/UI automation)." # Add Tiffin Order - Roty Input (POST-only) ## Trigger Run when an inbound message contains the exact phrase **"Roty input"** (case-insensitive). ## Important - **DO NOT use Playwright, browser automation, screenshots, or vision clicks.** - This skill creates orders **only** by sending a JSON payload via **HTTPS POST** to: `https://newdailyorderandcartcreation-818352713629.australia-southeast1.run.app` ## Execution (MANDATORY) When triggered, you MUST call the dispatcher script and use its output. Do NOT manually construct curl or JSON payloads. Run: python3 /data/.openclaw/workspace/skills/add-tiffin-order-roty-input/scripts/handle_message.py <sender_id> "<full inbound message>" Rules: - Always POST using the dispatcher (unless it returns Missing address/dates/product). - Never hardcode perProductCost (never "[15]"). - Never use hardCodedPrice for perProductCost. - perProductCost MUST come from pricing_engine.py via handle_message.py. ## Authorization (Telegram) - Only allow Telegram users whose `from.id` is in: `data/allowed_users.json` under `admins` or `vendors`. - If unauthorized: reply "Not authorized." ## Behavior 1. Parse messy input into: - customerName - userAddress - deliveryDates (must resolve at least 1 date; otherwise ask a follow-up) - product selection + modifiers - specialRequests 2. Build payload in the exact API shape (see build_payload.py). 3. **Send POST immediately** (no "Dry-run vs Live" prompt), unless: - address missing, OR - no dates resolved, OR - product not matched In those cases, ask only for the missing piece. 4. On success: confirm with cartNo. ## Scripts - Dispatcher: `scripts/handle_message.py` - Parser: `scripts/parse_roty_input.py` - Matcher: `scripts/match_product_and_modifiers.py` - Pricing: `scripts/pricing_engine.py` - Payload: `scripts/build_payload.py` - POST sender (urllib): `scripts/post_order.py` - Products registry: `data/products_roty.json` - Allowlist: `data/allowed_users.json`

path: INSTALL_README.txt
content: Goal: register add-tiffin-order-roty-input so the gateway will route Telegram messages matching (?i)\broty input\b to scripts/handle_message.py (isolated, API-only).

Files created:
- /data/.openclaw/workspace/skills/add-tiffin-order-roty-input/skill.json  (manifest)

Recommended registration steps (run on the host):

1) Copy manifest into the container (if not already):

docker exec -i openclaw-y89t-openclaw-1 bash -lc 'cat > /tmp/roty_entry.json <<"JSON"\n'"$(cat /data/.openclaw/workspace/skills/add-tiffin-order-roty-input/skill.json)"'\nJSON'

2) Try to install via ClawHub (preferred):

# From host: install the skill package using npx clawhub (container runs it)
docker exec -it openclaw-y89t-openclaw-1 bash -lc 'cd /data/.openclaw/workspace/skills && npx clawhub install ./add-tiffin-order-roty-input || echo "clawhub install failed; see fallback below"'

3) If ClawHub install doesn't apply for your build, use the OpenClaw skills CLI check/enable sequence:

# Check system-wide skill readiness
docker exec -it openclaw-y89t-openclaw-1 bash -lc 'openclaw skills check'

# List current registered skills
docker exec -it openclaw-y89t-openclaw-1 bash -lc 'openclaw skills list'

# If your build supports an enable/install command, use it. If not, Fall back to step 4.

4) Fallback immediate approach (exec wrapper + LLM routing until registration is available)
- I can create a small wrapper script that the LLM or any existing hook can call to run the handler with ROTIES_FORCE_API_ONLY enforced. (This is a temporary measure.)

Verification (after install):
- Restart container: docker restart openclaw-y89t-openclaw-1
- Run DRY_RUN: docker exec -it openclaw-y89t-openclaw-1 bash -lc 'cd /data/.openclaw/workspace/skills/add-tiffin-order-roty-input && DRY_RUN=1 python3 scripts/handle_message.py OPENCLAW "Roty input Test User 60 Kwinana St Glen Waverley veg 6 rotis tomorrow" --openclaw'
- Send a Telegram test message and check logs: docker logs -f openclaw-y89t-openclaw-1

If you run the install step(s) and paste the output here, I’ll verify and walk you through the DRY_RUN and live test.


path: README.md
content: Roty Tiffin - add-tiffin-order-roty-input

This skill automates placing Roty tiffin orders using the pricing_engine and build_payload scripts. It is intended for use with OpenClaw's skills system. 

Contents:
- scripts/handle_message.py — skill dispatcher
- scripts/pricing_engine.py — pricing logic
- scripts/build_payload.py — build order payload
- scripts/post_order.py — POSTs to order API + follow-ups
- data/products_roty.json — vendor/product list and prices

Please keep secrets and API keys out of this package; use environment variables instead.


path: data/allowed_users.json
content: {
  "admins": [
    "123",
    "7634134644"
  ],
  "vendors": [
    "123"
  ]
}

path: package.json
content: {
  "name": "add-tiffin-order-roty-input",
  "version": "0.1.0",
  "description": "Roty tiffin ordering skill (Python) - manifest for ClawHub/OpenClaw",
  "main": "scripts/handle_message.py",
  "clawhub": {
    "slug": "add-tiffin-order-roty-input",
    "entry": "scripts/handle_message.py"
  }
}


path: scripts/post_order.py
content: import json
import urllib.request
import urllib.error

ENDPOINT = 'https://newdailyorderandcartcreation-818352713629.australia-southeast1.run.app'


def post_order(payload, timeout=30):
    data = json.dumps(payload).encode('utf-8')
    req = urllib.request.Request(ENDPOINT, data=data, method='POST')
    req.add_header('Content-Type', 'application/json; charset=utf-8')
    try:
        with urllib.request.urlopen(req, timeout=timeout) as resp:
            status = resp.getcode()
            body = resp.read().decode('utf-8')
            try:
                body_json = json.loads(body)
            except Exception:
                body_json = body
            return status, body_json
    except urllib.error.HTTPError as e:
        try:
            body = e.read().decode('utf-8')
            body_json = json.loads(body)
        except Exception:
            body_json = e.reason
        return e.code, body_json
    except Exception as e:
        return 0, str(e)

if __name__ == '__main__':
    print('post_order helper (urllib)')


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)