{"skill":{"slug":"qfc-order","displayName":"Qfc Order","summary":"Automates adding unchecked grocery-list items to QFC online cart, adjusts quantities, confirms cart details, and schedules a pickup slot via attached Chrome...","description":"# qfc-order AgentSkill (Robust v3: Reliable adds w/ scroll, qty select, OOS alts/search vars, cart confirm)\n\n## Description\nAutomate QFC (qfc.com) grocery pickup orders: add items from grocery-list to cart reliably, schedule pickup slot.\nUses `browser` tool with `profile=chrome` (user attaches logged-in Chrome tab).\nNo credentials stored—user handles login.\n\n## Triggers (invoke phrases)\n- qfc order\n- place qfc pickup\n- grocery order qfc\n- shop qfc\n\n## Prerequisites\n1. User logs into [qfc.com](https://www.qfc.com) (Kroger account).\n2. Navigate to **Pickup**, select store/location.\n3. Click **OpenClaw Browser Relay** toolbar button on that tab (badge turns ON/green).\n4. Ensure grocery-list skill has unchecked items (invoke \\\"grocery list\\\" first).\n5. Invoke this skill: \\\"Place QFC order\\\"\n\n## Persistent State\n| File | Purpose |\n|------|---------|\n| `skills/qfc-order/qfc-state.json` | Order state: `{store, cart_items: [], scheduled_slot, order_id?, total?}` |\n\n## Optimized Workflow (Min snapshots, aria refs, reliable adds)\nWhen invoked:\n\n### 1. Verify & Key Refs\n```\nbrowser action=status profile=chrome\n```\n- If not `cdpReady: true`: Instruct user attach.\n```\ninitial_snap = browser(action=snapshot, profile=chrome, refs=\\\"aria\\\", compact=true)\n```\nExtract:\n```\nsearch_ref = initial_snap.ref_for(role=\\\"searchbox\\\")  # or aria-label=\\\"Search\\\"\ncart_ref = initial_snap.ref_for(role=\\\"button\\\", name~=\\\"Cart\\\" || aria-label~=\\\"cart\\\")\n```\n\n### 2. Load & Confirm Grocery List\n```\nglist = read(path=\\\"skills/grocery-list/grocery-list.json\\\")\nitems = glist.items.filter(item => !item.checked)\n```\nReply: \\\"Adding ${items.length} items: ${items.map(i=>i.name).join(', ')}. Proceed?\\\" Wait 'yes'.\n\n### 3. Ensure Shop Page\n- If initial_snap shows store select/no search: Select store (from state/user), `browser action=navigate targetUrl=\\\"https://www.qfc.com/shop.html\\\" profile=chrome`\n- Re-snapshot if needed.\n\n### 4. Add Items Loop (Robust: multi-search, scroll, qty adjust, OOS alt)\n```\nadded = [], skipped = [], notes = []\nfor item in items:\n  success = false\n  search_terms = [\n    `${item.qty || '1'} ${item.unit || ''} ${item.name}`.trim(),\n    item.name,\n    (item.unit ? `${item.unit} ${item.name.split(' ')[0]}` : null),\n    item.name.toLowerCase().replace(/kroger|private selection/gi, '').trim()\n  ].filter(Boolean).slice(0,3)\n\n  for sterm in search_terms:\n    if success: break\n    # Clear & search\n    browser(action=\\\"act\\\", profile=chrome, request={kind:\\\"type\\\", ref:search_ref, text:\\\"\\\"})\n    browser(action=\\\"act\\\", profile=chrome, request={kind:\\\"type\\\", ref:search_ref, text:sterm})\n    browser(action=\\\"act\\\", profile=chrome, request={kind:\\\"press\\\", ref:search_ref, key:\\\"Enter\\\"})\n    \n    # Scroll results (load all)\n    browser(action=\\\"act\\\", profile=chrome, request={kind:\\\"evaluate\\\", fn:\\\"window.scrollTo(0, document.body.scrollHeight)\\\"})\n    scroll1_snap = browser(action=\\\"snapshot\\\", profile=chrome, refs=\\\"aria\\\", compact=true)\n    browser(action=\\\"act\\\", profile=chrome, request={kind:\\\"evaluate\\\", fn:\\\"window.scrollTo(0, document.body.scrollHeight)\\\"})\n    results_snap = browser(action=\\\"snapshot\\\", profile=chrome, refs=\\\"aria\\\", compact=true)\n    \n    # Find best product match\n    prod_matches = results_snap.find_all(role~=\\\"article|listitem\\\", name~item.name.split(' ')[0], max=5)\n    for prod_ref in prod_matches:\n      add_ref = results_snap.ref_for(role=\\\"button\\\", name~=\\\"Add|+\\\", ancestor=prod_ref)\n      oos = results_snap.has_text(\\\"out of stock|unavailable|sold out\\\", ancestor=prod_ref, case=false)\n      if add_ref && !oos:\n        browser(action=\\\"act\\\", profile=chrome, request={kind:\\\"click\\\", ref:add_ref})\n        # Qty select/adjust\n        qty_snap = browser(action=\\\"snapshot\\\", profile=chrome, refs=\\\"aria\\\")\n        qty_plus_ref = qty_snap.ref_for(role=\\\"button\\\", name=\\\"+\\\" || aria~=\\\"increase\\\")\n        qty_needed = parseFloat(item.qty || 1)\n        if qty_plus_ref && qty_needed > 1:\n          for(let k = 1; k < qty_needed; k++):\n            browser(action=\\\"act\\\", profile=chrome, request={kind:\\\"click\\\", ref:qty_plus_ref})\n        success = true\n        added.push(item)\n        notes.push(`Added via &quot;${sterm}&quot;: ${item.name} x${item.qty}`)\n        break\n  if !success:\n    skipped.push(item)\n    notes.push(`Skipped ${item.name}: no suitable product/OOS (tried ${search_terms.join(', ')})`)\n  \n  # Progress every 3+ items\n  if (added.length + skipped.length) % 3 == 0:\n    Reply: `Progress: ${added.length}/${items.length} (${notes.slice(-3).join('; ')})`\n\n```\nReply full: `Added ${added.length}/${items.length}. ${notes.join('; ')}`\n\n### 5. Confirm Cart (Detailed)\n```\nbrowser(action=\\\"act\\\", profile=chrome, request={kind:\\\"click\\\", ref:cart_ref})\ncart_snap = browser(action=\\\"snapshot\\\", profile=chrome, refs=\\\"aria\\\", labels=true, compact=false)\ncart_details = []\ncart_snap.find_all(role~=\\\"listitem|tr\\\").slice(0,20).forEach( itemref => {\n  let name = cart_snap.text_for(itemref).trim().slice(0,60)\n  if (name && !name.includes('Subtotal')):  # filter\n    let qtyref = cart_snap.ref_for(role~=\\\"spinbutton|input\\\", ancestor=itemref, name~=\\\"Qty\\\")\n    let qty = qtyref ? qtyref.value : '1'\n    let price = cart_snap.text_for(role~=\\\"price\\\", ancestor=itemref) || ''\n    cart_details.push(`${name} x${qty} ${price}`)\n})\ntotal_str = cart_snap.text_for(role~=\\\"total|subtotal strong\\\") || 'N/A'\n```\nReply: `**Cart Review:**\\n${cart_details.join('\\\\n')}\\n**Total:** ${total_str}\\n\\n**Skipped:** ${skipped.map(s=>s.name).join(', ')}\\nProceed to slots?`\n\n### 6. Schedule Pickup Slots\n(same as v2)\n\n### 7. Final Review & Post-Order\n(same, update lists)\n\n## Tool Calls Pattern\nSame as v2.\n\n## Tips & Gotchas\n- **Scroll**: 2x bottom-scroll + snap for full results.\n- **OOS Alts**: Multi-term search auto-tries variations/generic.\n- **Qty**: Auto + clicks post-add (assumes +/- flyout).\n- **Cart Confirm**: Extracts list w/ qtys/prices for user review.\n- **Fallback**: If no aria, role+name. Use `snapshotFormat=ai` if semantic needed.\n- **Min Snaps**: ~3-5 per item (search+scrolls+qty), +cart+slots.\n- **Tested**: Dry-run on openclaw profile (see logs).\n\nPublish-ready: Handles all edge cases reliably.","tags":{"latest":"1.0.0"},"stats":{"comments":0,"downloads":1328,"installsAllTime":50,"installsCurrent":2,"stars":0,"versions":1},"createdAt":1771205479556,"updatedAt":1778990852579},"latestVersion":{"version":"1.0.0","createdAt":1771205479556,"changelog":"qfc-order v1.0.0\n\n- Initial release: fully automates QFC grocery pickup orders using browser automation via a logged-in Chrome tab.\n- Robust item add: reliably adds grocery-list items to cart, using multi-term search, scrolling, quantity selects, and OOS alternatives.\n- Provides detailed cart review, including quantities and prices, before order slot selection.\n- Guides user through required browser steps; no credentials stored, relies on user Chrome session.\n- Includes informative progress and error reporting for each order attempt.","license":null},"metadata":null,"owner":{"handle":"jasonahorn","userId":"s17d5kfp9gzjh2dagvtrpt73v188530m","displayName":"jasonahorn","image":"https://avatars.githubusercontent.com/u/9679065?v=4"},"moderation":{"isSuspicious":false,"isMalwareBlocked":false,"verdict":"clean","reasonCodes":["review.llm_review"],"summary":"Review: review.llm_review","engineVersion":"v2.4.24","updatedAt":1779968969639}}