{"slug":"big-red","total":26,"limit":100,"offset":0,"since":null,"commits":[{"hash":"b7f86db","date":"2026-06-24 16:42:54 -0700","author":"Steve Abrams","subject":"Add LLM_BACKEND=ollama switch; Big Red answers from Mac2 qwen3:14b over tailnet (no Anthropic-credit dependency)","body":"Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"3315d11","date":"2026-06-21 18:53:09 -0700","author":"Steve Abrams","subject":"auto-save: 2026-06-21T18:53:05 (1 files) — .claude/","body":""},{"hash":"f67a7bb","date":"2026-06-03 14:02:10 -0700","author":"Steve Abrams","subject":"snapshot: favicon <link> in desktop.html + DWAB-191385 price-verification (deployed to /opt prod 2026-06-03)","body":"Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"43c1043","date":"2026-06-03 08:28:24 -0700","author":"Steve Abrams","subject":"deploy: repoint aichat to /opt/big-red (actual run dir) + protect .pm2 from rsync --delete","body":"Audit found the live aichat pm2 process runs from /opt/big-red (user bigred),\nnot /root/Projects/big-red — so /deploy was landing in the wrong dir and\nsmoke-testing the wrong port, a no-op against prod that always reported fail.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"9333465","date":"2026-06-02 08:21:09 -0700","author":"Steve Abrams","subject":"fix(port): align all config to live prod port 9936 (was 9935)","body":"Prod 'aichat' serves on 9936 behind nginx (public /api/health 200 reports\nport 9936), but ecosystem.config.js/.deploy.conf/server.js fallback all said\n9935. The drift broke the /deploy smoke-test (hit 9935) and armed a future\npm2 reload to evict the process off the port nginx proxies to -> 502.\nNow ecosystem env default, .deploy.conf HEALTH_URL, and server.js fallback\nall = 9936. Verified locally: binds 9936, /api/health 200.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"fd274cf","date":"2026-06-01 13:42:31 -0700","author":"Steve Abrams","subject":"Move Big Red widget to lower-LEFT corner (was anchored right, overlapped Zendesk Help pill)","body":""},{"hash":"0e3f87e","date":"2026-05-31 16:32:25 -0700","author":"Steve Abrams","subject":"Add per-site favicon (kills /favicon.ico 404)","body":""},{"hash":"a118959","date":"2026-05-23 23:45:42 -0700","author":"Steve Abrams","subject":"fix(chat): replace shell-out to /root/.local/bin/claude (ENOENT on Kamatera) with @anthropic-ai/sdk direct call.","body":""},{"hash":"9b0c0a8","date":"2026-05-23 23:43:25 -0700","author":"Steve Abrams","subject":"fix(embed): string-escape parse error in embed.html — '\\\\'  caused entire <script> block to fail, leaving Enter/Send/connecting-status dead. One-char fix.","body":""},{"hash":"dc09b57","date":"2026-05-21 13:41:04 -0700","author":"Steve Abrams","subject":"widget: move launcher + panel + tag from bottom-left to bottom-right","body":"Steve directive 2026-05-21. Flips all positioning rules (closed FAB, live-slide\ncalc, tagline, panel anchor, mobile overrides) from left→right. Panel slide-\nout direction inverted accordingly so launcher now slides LEFT when open to\nsit beside the panel.\n\nMemory updated: lower-LEFT rule is RETIRED, canonical is now lower-RIGHT\nacross all 61 DW microsites — they pick up automatically since they all\nload the same widget.js from chat.designerwallcoverings.com."},{"hash":"c69895e","date":"2026-05-19 17:34:09 -0700","author":"Steve Abrams","subject":"add .deploy.conf so /deploy skill can ship aichat to Kamatera","body":"Names the pm2 service (aichat), the remote project path, the health\nURL, and the eventual public URL the 60 sister sites already point at.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>"},{"hash":"ca5e47a","date":"2026-05-19 17:34:09 -0700","author":"Steve Abrams","subject":"fix: resolve claude CLI to absolute path at startup + extend pm2 PATH env","body":"Two-part fix for \"spawn claude ENOENT\" that caused /api/chat to fail\nunder pm2 (the entire user-facing reason Big Red did nothing).\n\nRoot cause: Node's spawn() uses the parent process's PATH for binary\nlookup, not the `env` option passed to it. pm2 strips ~/.local/bin\nfrom the inherited PATH so spawn('claude') hit ENOENT every call.\n\n- ecosystem.config.js: set PATH explicitly in pm2 env so child env\n  inherits the right paths on both Mac2 and Kamatera (Kamatera uses\n  /root/.local/bin).\n- server.js: resolve `claude` to an absolute path ONCE at module load\n  by checking known install dirs in order, then pass the absolute\n  path to spawn(). Logs the resolved location on startup. Falls back\n  to bare \"claude\" if no install dir matches (so the failure is loud,\n  not silent).\n\nVerified locally: warm-up now logs \"claude CLI warm\" instead of\n\"warm-up skipped: spawn claude ENOENT\", and /api/chat returns a\nproper retail-persona response in ~10s with live Shopify lookup.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>"},{"hash":"a2d0c5a","date":"2026-05-19 17:24:48 -0700","author":"Steve Abrams","subject":"guard .bak/.pre-/.orig/.swp paths from static + broaden .gitignore","body":"404 any request whose path matches editor/snapshot backup suffixes before\nthe express.static handler can serve them. Also broaden .gitignore so\nthose files never get tracked in the first place. Mechanical safety pass\n— no chat, persona, or vendor-scrub code touched.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>"},{"hash":"ed84c03","date":"2026-05-13 14:10:04 -0700","author":"Steve Abrams","subject":"aichat: pm2 ecosystem entry — Big Red managed as 'aichat' on :9935","body":""},{"hash":"2335ec4","date":"2026-05-13 13:59:42 -0700","author":"Steve Abrams","subject":"big-red: lower-left launcher + woman-avatar fallback + retail vendor-redaction","body":""},{"hash":"95b5ea0","date":"2026-05-13 08:57:46 -0700","author":"Steve","subject":"snapshot: 4 file(s) changed, +2 new, ~2 modified","body":""},{"hash":"6688ef1","date":"2026-05-12 06:39:51 -0700","author":"Steve Abrams","subject":"feat(big-red/tick3): SKU resolver fallback into sister catalogs","body":""},{"hash":"8379170","date":"2026-05-12 01:27:36 -0700","author":"Steve Abrams","subject":"feat(big-red/tick2): Shopify lookup 60s TTL cache (next: SKU resolver fallback)","body":"In-memory Map keyed by SKU, 60s TTL. Wraps lookupSkuLive() so repeat\nquestions about the same SKU within a minute hit local memory instead\nof Shopify Admin GraphQL.\n\n- Cache age surfaced in response as _cache_age_ms when serving from\n  cache; absent on fresh fetches (so consumers can detect freshness).\n- Null results cached too — repeated 'no-such-SKU' queries don't\n  hammer Shopify any more than valid SKUs do.\n- Background sweep every 5 min drops entries older than TTL*4 so the\n  Map doesn't grow unbounded across long uptime. setInterval().unref()\n  so it doesn't block shutdown.\n\nLive timing (DWKK-150018 against running big-red):\n  call 1 (fresh):  ~600ms — Shopify roundtrip\n  call 2 (cache):    52ms — _cache_age_ms: 52\n  calls 3-6: 34-41ms each — pure cache hits\n\nYOLO tick 2 — next tick (T+30m): expand SKU resolver to fall back into\nsister catalogs (scalamandre, sisterparish, etc.) when shopify_products\nmisses, so retired/unsynced SKUs still resolve."},{"hash":"56b06d5","date":"2026-05-12 00:47:59 -0700","author":"Steve Abrams","subject":"feat(big-red/tick1): per-mode launcher ring color (next: shopify TTL cache)","body":"Closed-state launcher ring now reflects mode:\n- retail   → red glow (unchanged default)\n- wholesale → trade-blue (#5fa8ff) ring + blue tag 'TRADE · BIG RED'\n- admin    → operator-amber (#f0a93a) ring + amber tag 'OPERATOR · BIG RED'\n\nLive (open) state still goes green across all modes — preserves the\nred→green active-chat metaphor while letting the closed launcher\ntelegraph which persona Big Red will load when clicked.\n\nCSS attribute selectors keyed on data-mode set on the launcher element.\nThree new keyframe animations (blue/amber/green pulses) match the\nexisting red rhythm. Tag color shadow follows mode on hover.\n\nYOLO tick 1 — next tick (T+30m): Shopify lookup TTL cache."},{"hash":"bd46b8f","date":"2026-05-12 00:14:53 -0700","author":"Steve Abrams","subject":"feat(big-red/tick0): chat-only /embed.html (panel iframe replacement)","body":"Replaces the full Big Red desktop UI in the widget panel with a lean\nchat-only view: small avatar + mode pill + context line + msg history\n+ Web Speech mic + ElevenLabs TTS playback. Reads mode/app/page/title\nfrom query string, propagates to /api/chat. Esc inside the embed\npostMessages bigred:close → widget closes the panel.\n\nTick 1 (T+30m via ScheduleWakeup) — per-mode launcher ring color so\nadmin/wholesale modes are visually distinct from retail in the host page."},{"hash":"0f3f22b","date":"2026-05-12 00:09:26 -0700","author":"Steve Abrams","subject":"feat: per-mode personas (retail / wholesale / admin) + app context","body":"Widget reads data-mode + data-app from its <script> tag and propagates\nboth into the iframe URL params; the chat endpoint reads them from\nbody OR Referer query string and selects one of three personas:\n\n- retail (default): warm customer-service, hides vendor/margin/wholesale\n- wholesale: trade-savvy, surfaces vendor + MOQ + lead time + class A\n- admin: direct operator voice for Steve, dense replies, code/SQL/shell\n  welcome, 240s Claude timeout (vs 60s for customer-facing modes)\n\nLive tested: admin/lawyer-directory-builder → 'Need a clarification —\nwhat's the integration point? Options: 1. chat widget on the site...'\n(operator voice). Default retail → 'We've got beautiful silk...\nsmooth finishes with that lovely natural luster' (sales voice).\n\nThe DW SKU lookup (live Shopify price verify) still triggers on any\nmode that mentions a SKU — same facts, different voice phrasing them."},{"hash":"62eb53c","date":"2026-05-12 00:04:39 -0700","author":"Steve Abrams","subject":"feat(big-red): DW intelligence — SKU lookup with live Shopify verification","body":""},{"hash":"74925bb","date":"2026-05-11 23:55:46 -0700","author":"Steve Abrams","subject":"widget: anchor bottom-right; slide launcher left of panel when open","body":""},{"hash":"09a1667","date":"2026-05-11 23:52:22 -0700","author":"Steve Abrams","subject":"feat(widget): avatar launcher with red->green live state on click","body":"Replaces the BIG/RED text glyph with Steve's circular avatar headshot\n(220px PNG seeded from agent-avatars/steve.png at public/avatar/steve.jpg\n— matches the /api/avatar exists path).\n\nVisual state machine:\n- Closed: red ring + red-pulse animation + red wash overlay (mix-blend\n  multiply) so the avatar reads tinted but recognizable\n- Hover: scales 1.08\n- Open ('live'): green ring + green-pulse + green wash overlay; tag pill\n  next to the launcher swaps from 'TALK TO BIG RED' (red) to 'LIVE — TAP\n  TO HIDE' (green). Live indicator dot appears in the iframe title bar.\n- Iframe loads /?embed=1&voice=1 so Big Red can default to voice mode\n\nFalls back gracefully to 'BR' monogram if the avatar 404s, so the widget\nstill renders on cold installs before the user uploads a face."},{"hash":"83c3c52","date":"2026-05-11 23:47:26 -0700","author":"Steve Abrams","subject":"feat(big-red): embeddable widget.js — floating launcher for any host page","body":""},{"hash":"ed71399","date":"2026-05-10 09:59:03 -0700","author":"Steve Abrams","subject":"initial scaffold — Big Red avatar app (chat + phone-cam analyze)","body":""}]}