From ddc0e8eb9c0f1484f7481c602aee514f99e4642f Mon Sep 17 00:00:00 2001 From: steveseguin Date: Sun, 21 Jun 2026 19:00:53 -0400 Subject: [PATCH 01/30] chore(icons): restore Chrome Web Store listing icon Restore the `icons/webstore.svg` file that was previously missing or removed from the repository. This icon is used for the extension's Chrome Web Store listing. [auto-enhanced] --- icons/webstore.svg | 1 + 1 file changed, 1 insertion(+) create mode 100644 icons/webstore.svg diff --git a/icons/webstore.svg b/icons/webstore.svg new file mode 100644 index 000000000..c24e7087e --- /dev/null +++ b/icons/webstore.svg @@ -0,0 +1 @@ + \ No newline at end of file From ce7511c504142112ab8595bc462cf5d085d440af Mon Sep 17 00:00:00 2001 From: steveseguin Date: Sun, 21 Jun 2026 22:02:11 -0400 Subject: [PATCH 02/30] feat(tipjar): add donation type and source filters Introduce `tipjartype` and `tipjarsource` URL parameters to filter tips by unit (e.g., stars, bits) or platform (e.g., Facebook, YouTube). When a filter is active, the jar displays raw unit counts and uses separate persistent storage per filter combination. - **sources/facebook.js**: Add `donoValue` field (100 Stars = $1 USD) - **parameters.md**: Document new tip jar parameters (`tipjartype`, `tipjarunit`, `donationtype`, `tipjarsource`, `donationsource`, `tipjarunitlabel`, `persistent`, `controls`, `sound`, `hype`) - **popup.html**: Add dropdown UI for donation type and source filters - **tipjar.html**: Parse filters, update storage keys, CSV export, and history totals; adjust total display for native unit mode - **docs/event-reference.html**: Update Facebook Stars entry to mention `donoValue` [auto-enhanced] --- docs/event-reference.html | 4 +- parameters.md | 23 ++++- popup.html | 35 ++++++- sources/facebook.js | 3 + tipjar.html | 188 ++++++++++++++++++++++++++++++++++---- 5 files changed, 230 insertions(+), 23 deletions(-) diff --git a/docs/event-reference.html b/docs/event-reference.html index 253a45ab6..c9c422c7e 100644 --- a/docs/event-reference.html +++ b/docs/event-reference.html @@ -1233,7 +1233,7 @@

Facebook Live

Implementation: sources/facebook.js (DOM scraping) and optional Graph API bridge at sources/websocket/facebook.html

@@ -1253,7 +1253,7 @@

Facebook Live

- + diff --git a/parameters.md b/parameters.md index c81fa7eff..46449cffc 100644 --- a/parameters.md +++ b/parameters.md @@ -391,7 +391,24 @@ https://socialstream.ninja/dock.html?session=xxxxxxxxx&urlparameter=value | `filtertid` | comma-separated numbers | Filter by thread IDs | | `branded` | boolean | Shows channel icon | -## Other options for other overlays. - -WIP. +## Tip Jar & Goal Meter Parameters (`tipjar.html`) + +| Parameter | Values | Description | +|-----------|--------|-------------| +| `style` | `jar`, `meter`, `minimal` | Selects the tip jar display style | +| `goal` | number | Sets the target amount for the bar or jar | +| `title` | string | Sets the visible goal title | +| `tipjartype` | `usd`, `stars`, `bits`, `coins`, `diamonds`, `kicks`, `jewels`, `tokens`, `hearts`, `gold` | Counts only that donation unit/type. When set, the jar uses the raw unit count instead of converting to USD | +| `tipjarunit` or `donationtype` | same as `tipjartype` | Alias for `tipjartype` | +| `tipjarunitlabel` | string | Overrides the displayed unit label for a filtered unit bar | +| `tipjarsource` | source type such as `facebook`, `youtube`, `twitch`, `kick`, `tiktok`, `stripe`, `kofi`, `bmac`, `fourthwall` | Counts only donations from that source while preserving the normal USD conversion unless `tipjartype` is also set | +| `donationsource` | same as `tipjarsource` | Alias for `tipjarsource` | +| `persistent` | boolean | Keeps the current amount between sessions. Filtered bars use separate saved totals | +| `controls` | boolean | Shows reset/history/export controls | +| `sound` | boolean | Plays a sound on accepted donations | +| `hype` | boolean | Enables hype cup scoring mode | + +## Other options for other overlays. + +WIP. diff --git a/popup.html b/popup.html index c975127bd..4d2539efd 100644 --- a/popup.html +++ b/popup.html @@ -10781,10 +10781,41 @@

Goal Settings

-
+
+ + +
+
+ + +
+
- +
diff --git a/sources/facebook.js b/sources/facebook.js index 5899d6598..0cd82f4bf 100644 --- a/sources/facebook.js +++ b/sources/facebook.js @@ -408,6 +408,9 @@ data.chatmessage = msg; data.chatimg = chatimg; data.hasDonation = starsInfo ? starsInfo.text : ""; + if (starsInfo) { + data.donoValue = starsInfo.amount / 100; + } data.membership = "";; data.contentimg = contentimg; data.textonly = settings.textonlymode || false; diff --git a/tipjar.html b/tipjar.html index a417f0f4f..2ce3ff276 100644 --- a/tipjar.html +++ b/tipjar.html @@ -464,6 +464,10 @@

🏆 Top Dono const showCompletions = hypeMode && !urlParams.has('hidecompletions'); const completionDelayMs = readNumberParam('completiondelay', 3000, 0); const dedupeWindowMs = readNumberParam('dedupewindow', 8, 0) * 1000; + const donationTypeFilter = normalizeFilterValue(urlParams.get('tipjartype') || urlParams.get('tipjarunit') || urlParams.get('donationtype') || ''); + const sourceTypeFilter = normalizeFilterList(urlParams.get('tipjarsource') || urlParams.get('donationsource') || ''); + const nativeUnitMode = !!donationTypeFilter; + const nativeUnitLabel = urlParams.get('tipjarunitlabel') || getDonationTypeLabel(donationTypeFilter); // Socket server parameters const hasServerParam = urlParams.has('server') || urlParams.has('server2'); @@ -511,9 +515,10 @@

🏆 Top Dono } // Tracking variables - const amountStorageKey = hypeMode ? 'tipjar_hype_amount' : 'tipjar_amount'; - const historyStorageKey = hypeMode ? 'tipjar_hype_history' : 'tipjar_history'; - const completionsStorageKey = 'tipjar_hype_completions'; + const storageSuffix = buildTipJarStorageSuffix(); + const amountStorageKey = (hypeMode ? 'tipjar_hype_amount' : 'tipjar_amount') + storageSuffix; + const historyStorageKey = (hypeMode ? 'tipjar_hype_history' : 'tipjar_history') + storageSuffix; + const completionsStorageKey = 'tipjar_hype_completions' + storageSuffix; let currentAmount = persistent ? (parseFloat(localStorage.getItem(amountStorageKey)) || 0) : 0; let completionCount = persistent ? (parseInt(localStorage.getItem(completionsStorageKey) || '0', 10) || 0) : 0; let completionResetTimer = null; @@ -836,6 +841,137 @@

🏆 Top Dono document.addEventListener(eventName, primeDonationSound); }); + function normalizeFilterValue(value) { + return String(value || '').trim().toLowerCase(); + } + + function normalizeFilterList(value) { + return String(value || '').split(',').map(function(item) { + return normalizeFilterValue(item); + }).filter(function(item) { + return item && item !== 'all' && item !== 'any'; + }); + } + + function buildTipJarStorageSuffix() { + const parts = []; + if (donationTypeFilter) { + parts.push('type_' + donationTypeFilter.replace(/[^a-z0-9_-]/g, '')); + } + if (sourceTypeFilter.length) { + parts.push('source_' + sourceTypeFilter.join('_').replace(/[^a-z0-9_-]/g, '')); + } + return parts.length ? '_' + parts.join('_') : ''; + } + + function getDonationTypeLabel(type) { + const labels = { + usd: 'USD', + cash: 'USD', + stars: 'Stars', + star: 'Stars', + bits: 'bits', + bit: 'bits', + cheer: 'bits', + cheers: 'bits', + coins: 'coins', + coin: 'coins', + diamonds: 'Diamonds', + diamond: 'Diamonds', + kicks: 'KICKs', + kick: 'KICKs', + jewels: 'Jewels', + jewel: 'Jewels', + tokens: 'tokens', + token: 'tokens', + hearts: 'hearts', + heart: 'hearts', + gold: 'gold' + }; + return labels[type] || type || 'units'; + } + + function parseDonationAmount(rawDonation) { + const match = String(rawDonation || '').match(/-?\d[\d.,]*(?:\s\d{3})*/); + if (!match) return null; + + let numericText = match[0].replace(/\s/g, ''); + const lastComma = numericText.lastIndexOf(','); + const lastDot = numericText.lastIndexOf('.'); + let decimalSeparator = ''; + + if (lastComma !== -1 && lastDot !== -1) { + decimalSeparator = lastComma > lastDot ? ',' : '.'; + } else if (lastComma !== -1 || lastDot !== -1) { + const separator = lastComma !== -1 ? ',' : '.'; + const lastSeparator = lastComma !== -1 ? lastComma : lastDot; + const decimals = numericText.length - lastSeparator - 1; + const count = (numericText.match(new RegExp('\\' + separator, 'g')) || []).length; + const integerPart = numericText.slice(0, lastSeparator).replace('-', ''); + if (decimals > 0 && (decimals !== 3 || integerPart === '0') && count === 1) { + decimalSeparator = separator; + } + } + + if (decimalSeparator) { + const thousandsSeparator = decimalSeparator === ',' ? '.' : ','; + numericText = numericText.split(thousandsSeparator).join(''); + numericText = numericText.replace(decimalSeparator, '.'); + } else { + numericText = numericText.replace(/[.,]/g, ''); + } + + const amount = parseFloat(numericText); + return isNaN(amount) ? null : amount; + } + + function getDonationUnitInfo(rawDonation, source) { + const raw = String(rawDonation || ''); + const amount = parseDonationAmount(raw); + if (amount === null || amount <= 0) return null; + + const text = raw.toLowerCase(); + const sourceKey = normalizeFilterValue(source); + + if (/\bstars?\b/.test(text)) return { type: 'stars', amount, label: 'Stars' }; + if (/\b(bits?|cheers?)\b/.test(text)) return { type: 'bits', amount, label: 'bits' }; + if (/\bcoins?\b/.test(text)) return { type: 'coins', amount, label: 'coins' }; + if (/\bdiamonds?\b/.test(text)) return { type: 'diamonds', amount, label: 'Diamonds' }; + if (/\bkicks?\b/.test(text)) return { type: 'kicks', amount, label: 'KICKs' }; + if (/\bjewels?\b/.test(text)) return { type: 'jewels', amount, label: 'Jewels' }; + if (/\btokens?\b/.test(text)) return { type: 'tokens', amount, label: 'tokens' }; + if (/\bhearts?\b/.test(text)) return { type: 'hearts', amount, label: 'hearts' }; + if (/\bgold\b/.test(text)) return { type: 'gold', amount, label: 'gold' }; + + const hasCashMarker = /[$]|\b(?:usd|cad|aud|nzd|eur|gbp|jpy|cny|hkd|twd|krw|inr|brl|mxn|ars|clp|cop|pen|php|sgd|myr|thb|idr|vnd|ils|try|zar|sek|nok|dkk|chf|pln|czk|huf|ron|rub|uah)\b/i.test(raw) || + /[\u20ac\u00a3\u00a5\u20b9\u20a9\u20aa\u20b1\u0e3f\u20ab\u20b4\u20a6\u20a1\u20b2\u20b5\u20ad\u20ae\u20b8\u20ba\u20bd\u20bc\u20be\u20bf]/.test(raw); + if (hasCashMarker || sourceKey === 'stripe' || sourceKey === 'kofi' || sourceKey === 'bmac' || sourceKey === 'fourthwall') { + return { type: 'usd', amount, label: 'USD' }; + } + + return { type: '', amount, label: nativeUnitLabel || 'units' }; + } + + function donationMatchesTypeFilter(unitInfo, rawDonation) { + if (!donationTypeFilter) return true; + if (!unitInfo || !unitInfo.type) return false; + + const filter = donationTypeFilter === 'cash' ? 'usd' : donationTypeFilter; + const unitType = unitInfo.type === 'cash' ? 'usd' : unitInfo.type; + if (filter === unitType) return true; + + const raw = String(rawDonation || '').toLowerCase(); + const escapedFilter = filter.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + return new RegExp('(^|\\s)' + escapedFilter + 's?(?=\\s|$)').test(raw); + } + + function passesTipJarSourceFilter(data) { + if (!sourceTypeFilter.length) return true; + const meta = getMeta(data); + const source = normalizeFilterValue(data.type || data.platform || meta.source || ''); + return sourceTypeFilter.indexOf(source) !== -1; + } + function readNumberParam(name, fallback, minValue) { const raw = urlParams.get(name); if (raw === null || raw === '') return fallback; @@ -854,6 +990,9 @@

🏆 Top Dono if (hypeMode) { return `${formatNumber(value)} ${unitLabel}`; } + if (nativeUnitMode) { + return `${formatNumber(value)} ${nativeUnitLabel}`; + } const num = Number(value) || 0; return `$${forceCents ? num.toFixed(2) : formatNumber(num)}`; } @@ -873,12 +1012,12 @@

🏆 Top Dono return { amount: null, currency: '', display: '' }; } - const numericMatch = raw.match(/-?\d+(?:[.,]\d+)?/); + const numericMatch = raw.match(/-?\d[\d.,]*(?:\s\d{3})*/); let amount = null; let currency = ''; if (numericMatch) { - amount = parseFloat(numericMatch[0].replace(',', '.')); + amount = parseDonationAmount(raw); const before = raw.slice(0, numericMatch.index).trim(); const after = raw.slice(numericMatch.index + numericMatch[0].length).trim(); currency = `${before} ${after}`.trim(); @@ -1141,6 +1280,7 @@

🏆 Top Dono function processHypeContribution(data) { const contribution = buildHypeContribution(data); if (!contribution) return; + if (donationTypeFilter && contribution.kind !== 'donation') return; if (isDuplicateContribution(data, contribution)) return; if (contribution.kind === 'donation') { @@ -1153,7 +1293,12 @@

🏆 Top Dono function processTip(rawDonation, donator, sourceType, contribution) { const source = sourceType ? String(sourceType).toLowerCase() : ''; - const tipValue = convertToUSD(rawDonation, source); + const unitInfo = getDonationUnitInfo(rawDonation, source); + if (donationTypeFilter && !donationMatchesTypeFilter(unitInfo, rawDonation)) { + return; + } + + const tipValue = nativeUnitMode && unitInfo ? unitInfo.amount : convertToUSD(rawDonation, source); if (isNaN(tipValue) || tipValue <= 0) { console.warn('Ignoring invalid donation value:', rawDonation); @@ -1162,8 +1307,8 @@

🏆 Top Dono const parsedDonation = parseDonationString(rawDonation); const storedAmount = parsedDonation.amount !== null ? parsedDonation.amount : tipValue; - const storedCurrency = parsedDonation.currency || 'USD'; - const displayLabel = parsedDonation.display || `$${tipValue.toFixed(2)}`; + const storedCurrency = nativeUnitMode ? (unitInfo && unitInfo.label ? unitInfo.label : nativeUnitLabel) : (parsedDonation.currency || 'USD'); + const displayLabel = nativeUnitMode ? `${formatNumber(tipValue)} ${storedCurrency}` : (parsedDonation.display || `$${tipValue.toFixed(2)}`); const goalValue = hypeMode ? tipValue * donationPointRate : tipValue; const donation = { @@ -1176,7 +1321,8 @@

🏆 Top Dono count: 1, amount: storedAmount, currency: storedCurrency, - usdValue: tipValue, + usdValue: nativeUnitMode ? undefined : tipValue, + unitValue: nativeUnitMode ? tipValue : undefined, points: hypeMode ? goalValue : undefined, raw: parsedDonation.display || '' }; @@ -1215,6 +1361,10 @@

🏆 Top Dono return; } + if (!passesTipJarSourceFilter(data)) { + return; + } + if (hypeMode) { processHypeContribution(data); return; @@ -1360,7 +1510,7 @@

🏆 Top Dono let csv = hypeMode ? 'Timestamp,Type,Name,Recipient,Count,Points,Amount,Currency,USD Value,Source,Event,Raw\n' - : 'Timestamp,Donator,Amount,Currency,USD Value\n'; + : 'Timestamp,Donator,Amount,Currency,USD Value,Unit Value,Source,Raw\n'; donationHistory.forEach(donation => { const date = new Date(donation.timestamp).toLocaleString(); if (hypeMode) { @@ -1379,7 +1529,9 @@

🏆 Top Dono csvCell(donation.raw || '') ].join(',') + '\n'; } else { - csv += `${csvCell(date)},${csvCell(donation.donator)},${donation.amount},${donation.currency},${donation.usdValue.toFixed(2)}\n`; + const usdValue = donation.usdValue !== undefined ? Number(donation.usdValue).toFixed(2) : ''; + const unitValue = donation.unitValue !== undefined ? formatNumber(donation.unitValue) : ''; + csv += `${csvCell(date)},${csvCell(donation.donator)},${donation.amount},${csvCell(donation.currency)},${usdValue},${unitValue},${csvCell(donation.source || '')},${csvCell(donation.raw || '')}\n`; } }); @@ -1408,7 +1560,9 @@

🏆 Top Dono const kind = donation.kind || 'donation'; const detail = hypeMode ? `${formatGoalValue(donation.points || 0)} - ${kind}${donation.count ? ` x${donation.count}` : ''}${donation.recipient ? ` - recipient: ${donation.recipient}` : ''}` - : `${donation.amount} ${donation.currency} ($${donation.usdValue.toFixed(2)} USD)`; + : (donation.usdValue !== undefined + ? `${donation.amount} ${donation.currency} ($${Number(donation.usdValue).toFixed(2)} USD)` + : `${formatNumber(donation.unitValue || donation.amount || 0)} ${donation.currency}`); item.style.cssText = 'margin-bottom: 10px; padding: 10px; background: rgba(255,255,255,0.1); border-radius: 5px;'; item.innerHTML = `
${donation.donator}
@@ -1419,10 +1573,10 @@

🏆 Top Dono }); // Add total at the bottom - const total = donationHistory.reduce((sum, d) => sum + (hypeMode ? (d.points || 0) : d.usdValue), 0); + const total = donationHistory.reduce((sum, d) => sum + (hypeMode ? (d.points || 0) : (d.unitValue !== undefined ? d.unitValue : d.usdValue || 0)), 0); const totalDiv = document.createElement('div'); totalDiv.style.cssText = 'margin-top: 20px; padding-top: 20px; border-top: 1px solid #666; font-size: 18px; font-weight: bold;'; - totalDiv.innerHTML = hypeMode ? `Total: ${formatGoalValue(total)}` : `Total: $${total.toFixed(2)} USD`; + totalDiv.innerHTML = hypeMode || nativeUnitMode ? `Total: ${formatGoalValue(total)}` : `Total: $${total.toFixed(2)} USD`; historyList.appendChild(totalDiv); } @@ -1461,6 +1615,7 @@

🏆 Top Dono if (!donatorTotals[donation.donator]) { donatorTotals[donation.donator] = { totalUSD: 0, + totalUnits: 0, totalPoints: 0, count: 0, gifts: 0, @@ -1469,6 +1624,7 @@

🏆 Top Dono }; } donatorTotals[donation.donator].totalUSD += donation.usdValue || 0; + donatorTotals[donation.donator].totalUnits += donation.unitValue !== undefined ? donation.unitValue : 0; donatorTotals[donation.donator].totalPoints += donation.points || 0; donatorTotals[donation.donator].count += 1; if (donation.kind === 'gift') { @@ -1487,7 +1643,7 @@

🏆 Top Dono // Sort by points in hype mode, otherwise by total USD. const sortedDonators = Object.entries(donatorTotals) - .sort((a, b) => hypeMode ? b[1].totalPoints - a[1].totalPoints : b[1].totalUSD - a[1].totalUSD) + .sort((a, b) => hypeMode ? b[1].totalPoints - a[1].totalPoints : (nativeUnitMode ? b[1].totalUnits - a[1].totalUnits : b[1].totalUSD - a[1].totalUSD)) .slice(0, 10); // Top 10 sortedDonators.forEach(([donator, data], index) => { @@ -1500,7 +1656,7 @@

🏆 Top Dono const currencyBreakdown = Object.entries(data.currencies) .map(([currency, amount]) => `${amount.toFixed(2)} ${currency}`) .join(' + '); - const scoreLabel = hypeMode ? formatGoalValue(data.totalPoints) : `$${data.totalUSD.toFixed(2)}`; + const scoreLabel = hypeMode ? formatGoalValue(data.totalPoints) : (nativeUnitMode ? formatGoalValue(data.totalUnits) : `$${data.totalUSD.toFixed(2)}`); const subLine = hypeMode ? `${data.count} contribution${data.count > 1 ? 's' : ''}${data.subs ? ` - ${data.subs} sub/member` : ''}${data.gifts ? ` - ${data.gifts} gifted` : ''}` : `${data.count} donation${data.count > 1 ? 's' : ''}`; From eac27e97b830d2070010e2c9f07558936975b660 Mon Sep 17 00:00:00 2001 From: steveseguin Date: Sun, 21 Jun 2026 22:46:53 -0400 Subject: [PATCH 03/30] feat(tipjar): add fluid goal bar style with recurring levels - Introduce new "bar" display style for the tip jar/ goal meter with configurable fill colors (fillstart, fillend) and fill behavior (progress, gradient, solid) - Add recurring level support via `levelsize` parameter, enabling repeating goal increments - Implement additional customization parameters: barheight, noliquid, theme, celebration - Update popup.html UI with controls for fill color, fill mode, and recurring increment - Document all new parameters in parameters.md - Bump manifest version to 3.50.1 [auto-enhanced] --- manifest.json | 2 +- parameters.md | 424 +++++----- popup.html | 23 + tipjar.html | 2235 ++++++++++++++++++++++++++++--------------------- 4 files changed, 1507 insertions(+), 1177 deletions(-) diff --git a/manifest.json b/manifest.json index 59c5d7491..3f7e2a181 100644 --- a/manifest.json +++ b/manifest.json @@ -2,7 +2,7 @@ "name": "Social Stream Ninja", "description": "Capture live chat from 100+ supported sites and consolidate it into a single dashboard for live production workflows", "manifest_version": 3, - "version": "3.50.0", + "version": "3.50.1", "homepage_url": "http://socialstream.ninja/", "browser_specific_settings": { "gecko": { diff --git a/parameters.md b/parameters.md index 46449cffc..6b305893e 100644 --- a/parameters.md +++ b/parameters.md @@ -26,15 +26,15 @@ https://socialstream.ninja/dock.html?session=xxxxxxxxx&urlparameter=value | Parameter | Values | Description | |-----------|---------|-------------| -| `session` or `s` or `id` | string | Sets the session ID for connecting to the chat | +| `session` or `s` or `id` | string | Sets the session ID for connecting to the chat | | `password` | string | Sets a password for the session | | `scale` | float | Adjusts the size scaling of the overlay (default: 1.0) | | `limit` | number | Maximum number of messages to show before older ones are removed | | `opacity` | 0.0-1.0 | Sets the opacity of the main overlay window | -| `hidemenu` or `nomenu` | boolean or "2" | Hides the menu bar. Value of "2" keeps scroll lock functionality | +| `hidemenu` or `nomenu` | boolean or "2" | Hides the menu bar. Value of "2" keeps scroll lock functionality | | `css` | URL or CSS string | Applies custom CSS styling via URL or direct CSS | -| `cssb64` or `b64css` or `base64css` or `cssbase64` | base64 string | Applies custom CSS styling via base64 encoded string | -| `js` or `base64js` or `b64js` or `jsbase64` or `jsb64` | URL or base64 string | Loads external JavaScript (limited to trusted hosting contexts) | +| `cssb64` or `b64css` or `base64css` or `cssbase64` | base64 string | Applies custom CSS styling via base64 encoded string | +| `js` or `base64js` or `b64js` or `jsbase64` or `jsb64` | URL or base64 string | Loads external JavaScript (limited to trusted hosting contexts) | | `label` | string | Assigns a label to this instance | ### Visual Style Parameters @@ -43,64 +43,64 @@ https://socialstream.ninja/dock.html?session=xxxxxxxxx&urlparameter=value |-----------|---------|-------------| | `darkmode` | boolean | Enables dark theme with black background | | `lightmode` | boolean | Enables light theme with white background | -| `transparent` or `transparency` | boolean | Makes background transparent and hides scrollbar | -| `chroma` | hex color | Sets a specific background color (without #) | -| `blur` or `blurred` | number | Applies blur effect to messages (value in pixels) | -| `noblur` | boolean | Disables blur rendering (including hidden-source blur and timed-out blur) | -| `compact` or `overlaymode` | boolean | Enables compact mode with less spacing | -| `padding` | number | Sets padding between messages in pixels | +| `transparent` or `transparency` | boolean | Makes background transparent and hides scrollbar | +| `chroma` | hex color | Sets a specific background color (without #) | +| `blur` or `blurred` | number | Applies blur effect to messages (value in pixels) | +| `noblur` | boolean | Disables blur rendering (including hidden-source blur and timed-out blur) | +| `compact` or `overlaymode` | boolean | Enables compact mode with less spacing | +| `padding` | number | Sets padding between messages in pixels | | `largeavatar` | boolean | Shows larger user avatars on the left side | -| `emoji` or `emojis` | number | Sets emoji size scaling (percentage, default: 140) | -| `nooutline` | boolean | Removes text outline effects | -| `font` | string | Sets custom font family | -| `googlefont` | string | Loads and uses a Google Font | -| `color` or `colorednames` | boolean | Uses platform accent colors for usernames | -| `fontcolor` | hex color | Overrides the body text color | -| `namecolor` | hex color | Overrides the username text color | -| `fontweight` | number or keyword | Sets font weight for message text | -| `nameweight` | number or keyword | Sets font weight for usernames | -| `outlinewidth` | number | Width (px) of the outer outline highlight | -| `outlinecolor` | hex color | Color applied to the outer outline highlight | -| `strokewidth` or `stroke` | number | Width (px) for the text stroke effect | -| `strokecolor` or `strokeColor` | hex color (alpha supported) | Color applied to the text stroke effect (accepts 8-digit hex/rgba for transparency) | -| `border` | hex color | Adds a profile image border using the provided color (without `#`) | -| `pressedcolor` | hex color or empty | Custom highlight color for pinned/featured states | -| `donationhighlightcolor` | hex/color | Custom donation row highlight color; 6-digit colors are shown with stronger shading automatically | -| `memberhighlightcolor` | hex/color | Custom member row highlight color; 6-digit colors are shown with stronger shading automatically | -| `firsttimehighlightcolor` | hex/color | Custom first-time chatter row highlight color; 6-digit colors are shown with stronger shading automatically | -| `questionhighlightcolor` | hex/color | Custom question row highlight color; 6-digit colors are shown with stronger shading automatically | -| `hideshadow` | boolean | Removes alternating card drop shadows | -| `largecontent` | boolean | Enlarges embedded content or image cards | -| `donationright` | number | Sets donation amount margin-right in pixels | -| `bubbleopacity` | 0.0-1.0 | Sets message bubble background opacity | -| `namebubblecolor` | hex/color | Background color for the rounded name bubble | -| `namebubbletext` | hex/color | Text color for the rounded name bubble | -| `namebubbleradius` | number or CSS length | Border radius for the rounded name bubble | -| `namebubblepadding` | CSS padding string | Padding for the rounded name bubble | -| `bolder` | boolean | Applies a thicker drop shadow around text | -| `thinner` | boolean | Applies a thinner drop shadow around text | -| `unhighlight` | boolean | Uses an alternate style when un-featuring messages | -| `nofeaturedhightlight` | boolean | Disables the flash highlight when a card is featured | -| `nomemberhighlight` | boolean | Disables highlight color for member messages | -| `noquestionhightlight` | boolean | Disables highlight color for question cards | +| `emoji` or `emojis` | number | Sets emoji size scaling (percentage, default: 140) | +| `nooutline` | boolean | Removes text outline effects | +| `font` | string | Sets custom font family | +| `googlefont` | string | Loads and uses a Google Font | +| `color` or `colorednames` | boolean | Uses platform accent colors for usernames | +| `fontcolor` | hex color | Overrides the body text color | +| `namecolor` | hex color | Overrides the username text color | +| `fontweight` | number or keyword | Sets font weight for message text | +| `nameweight` | number or keyword | Sets font weight for usernames | +| `outlinewidth` | number | Width (px) of the outer outline highlight | +| `outlinecolor` | hex color | Color applied to the outer outline highlight | +| `strokewidth` or `stroke` | number | Width (px) for the text stroke effect | +| `strokecolor` or `strokeColor` | hex color (alpha supported) | Color applied to the text stroke effect (accepts 8-digit hex/rgba for transparency) | +| `border` | hex color | Adds a profile image border using the provided color (without `#`) | +| `pressedcolor` | hex color or empty | Custom highlight color for pinned/featured states | +| `donationhighlightcolor` | hex/color | Custom donation row highlight color; 6-digit colors are shown with stronger shading automatically | +| `memberhighlightcolor` | hex/color | Custom member row highlight color; 6-digit colors are shown with stronger shading automatically | +| `firsttimehighlightcolor` | hex/color | Custom first-time chatter row highlight color; 6-digit colors are shown with stronger shading automatically | +| `questionhighlightcolor` | hex/color | Custom question row highlight color; 6-digit colors are shown with stronger shading automatically | +| `hideshadow` | boolean | Removes alternating card drop shadows | +| `largecontent` | boolean | Enlarges embedded content or image cards | +| `donationright` | number | Sets donation amount margin-right in pixels | +| `bubbleopacity` | 0.0-1.0 | Sets message bubble background opacity | +| `namebubblecolor` | hex/color | Background color for the rounded name bubble | +| `namebubbletext` | hex/color | Text color for the rounded name bubble | +| `namebubbleradius` | number or CSS length | Border radius for the rounded name bubble | +| `namebubblepadding` | CSS padding string | Padding for the rounded name bubble | +| `bolder` | boolean | Applies a thicker drop shadow around text | +| `thinner` | boolean | Applies a thinner drop shadow around text | +| `unhighlight` | boolean | Uses an alternate style when un-featuring messages | +| `nofeaturedhightlight` | boolean | Disables the flash highlight when a card is featured | +| `nomemberhighlight` | boolean | Disables highlight color for member messages | +| `noquestionhightlight` | boolean | Disables highlight color for question cards | ### Layout Parameters | Parameter | Values | Description | |-----------|---------|-------------| -| `horizontal` | boolean | Makes messages scroll horizontally | -| `horizontalreverse` | boolean | When horizontal is enabled, enters left-to-right mode so newest messages slide in from the left | +| `horizontal` | boolean | Makes messages scroll horizontally | +| `horizontalreverse` | boolean | When horizontal is enabled, enters left-to-right mode so newest messages slide in from the left | | `alignbottom` | boolean | Makes messages start from bottom | | `alignright` | boolean | Aligns messages to the right side | | `rtl` | boolean | Enables right-to-left text direction | | `fixed` | boolean | Makes messages overlap each other | -| `twolines` | boolean | Places messages on a separate line below usernames | -| `split` | boolean | Enables split mode for message alignment | -| `bubble` | boolean | Styles messages as chat bubbles | -| `namebubble` | boolean | Adds a separate rounded bubble behind usernames (bubble mode) | -| `fadedtop` | boolean | Fades out the top of the overlay | -| `reverse` | boolean | Displays the feed in reverse order (newest at the top) | -| `dropdown` | boolean | Enables reverse order with drop-down style animations | +| `twolines` | boolean | Places messages on a separate line below usernames | +| `split` | boolean | Enables split mode for message alignment | +| `bubble` | boolean | Styles messages as chat bubbles | +| `namebubble` | boolean | Adds a separate rounded bubble behind usernames (bubble mode) | +| `fadedtop` | boolean | Fades out the top of the overlay | +| `reverse` | boolean | Displays the feed in reverse order (newest at the top) | +| `dropdown` | boolean | Enables reverse order with drop-down style animations | ### Animation Parameters @@ -110,13 +110,13 @@ https://socialstream.ninja/dock.html?session=xxxxxxxxx&urlparameter=value | `fadeout` | boolean | Enables fade-out animation when removing messages | | `swipeleft` | boolean | Messages slide in from the right | | `swiperight` | boolean | Messages slide in from the left | -| `swipeup` | boolean | Messages slide up from bottom | -| `smooth` | boolean | Enables smooth scrolling | -| `animatein` | string | Sets specific entrance animation (see animate.css) | -| `animateout` | string | Sets specific exit animation (see animate.css) | -| `typewriter` | boolean or number | Types chat text letter-by-letter with a blinking cursor; optional numeric value sets the per-character delay (ms) while messages wait for the current typing to finish | - -### Message Display Parameters +| `swipeup` | boolean | Messages slide up from bottom | +| `smooth` | boolean | Enables smooth scrolling | +| `animatein` | string | Sets specific entrance animation (see animate.css) | +| `animateout` | string | Sets specific exit animation (see animate.css) | +| `typewriter` | boolean or number | Types chat text letter-by-letter with a blinking cursor; optional numeric value sets the per-character delay (ms) while messages wait for the current typing to finish | + +### Message Display Parameters | Parameter | Values | Description | |-----------|---------|-------------| @@ -125,24 +125,24 @@ https://socialstream.ninja/dock.html?session=xxxxxxxxx&urlparameter=value | `trim` | number | Trims messages longer than specified characters | | `trimname` | number | Trims usernames longer than specified characters | | `hidenames` | boolean | Hides usernames completely | -| `firstnamesonly` or `firstname` or `firstnames` | boolean | Shows only first names of users | +| `firstnamesonly` or `firstname` or `firstnames` | boolean | Shows only first names of users | | `hidesource` | boolean | Hides the source platform icons (YouTube, Twitch, etc.) | -| `noavatar` or `noavatars` | boolean | Hides user avatars | -| `nobadges` or `hidebadges` | boolean | Hides user badges | -| `limitbadges` | number | Limits number of badges shown per message | -| `notime` or `notimestamp` or `nodate` | boolean | Hides timestamp | -| `24hr` | boolean | Displays timestamps using 24-hour format | -| `sequence` | boolean | Hides name/icons if sequential messages from same user | -| `attachmentsonly` | boolean | Displays only messages that include an attached image or clip | -| `hidequestions` | boolean | Hides cards flagged as questions | -| `onlyquestions` | boolean | Shows only messages that contain question metadata | -| `hidenumbers` | boolean | Hides messages that contain only digits | -| `showsourcename` | boolean | Displays the originating platform label on each card | -| `showviewercount` | boolean | Shows the current viewer count indicator | -| `nocolon` | boolean | Removes the colon between username and message body | -| `namefilter` | boolean | Applies filters to usernames instead of message text | -| `stripreplyto` | boolean | Removes “replying to” prefaces from imported messages | -| `normalize` | boolean | Normalizes characters (e.g., removes diacritics) for comparisons | +| `noavatar` or `noavatars` | boolean | Hides user avatars | +| `nobadges` or `hidebadges` | boolean | Hides user badges | +| `limitbadges` | number | Limits number of badges shown per message | +| `notime` or `notimestamp` or `nodate` | boolean | Hides timestamp | +| `24hr` | boolean | Displays timestamps using 24-hour format | +| `sequence` | boolean | Hides name/icons if sequential messages from same user | +| `attachmentsonly` | boolean | Displays only messages that include an attached image or clip | +| `hidequestions` | boolean | Hides cards flagged as questions | +| `onlyquestions` | boolean | Shows only messages that contain question metadata | +| `hidenumbers` | boolean | Hides messages that contain only digits | +| `showsourcename` | boolean | Displays the originating platform label on each card | +| `showviewercount` | boolean | Shows the current viewer count indicator | +| `nocolon` | boolean | Removes the colon between username and message body | +| `namefilter` | boolean | Applies filters to usernames instead of message text | +| `stripreplyto` | boolean | Removes “replying to” prefaces from imported messages | +| `normalize` | boolean | Normalizes characters (e.g., removes diacritics) for comparisons | ### Filtering Parameters @@ -152,56 +152,56 @@ https://socialstream.ninja/dock.html?session=xxxxxxxxx&urlparameter=value | `hideshortmessages` | number | Hides messages shorter than specified length | | `noemojisonly` | boolean | Filters out messages containing only emojis | | `stripemoji` | boolean | Removes all emojis from messages | -| `striphtml` or `strip` | boolean | Removes HTML formatting from messages | +| `striphtml` or `strip` | boolean | Removes HTML formatting from messages | | `striplinks` | boolean | Removes links from messages | | `activelinks` | boolean | Makes URLs clickable | | `shortlink` | boolean | Shortens displayed links | | `onlytwitch` | boolean | Shows only Twitch messages | -| `hidetwitch` | boolean | Hides Twitch messages | -| `hidefrom` or `exclude` | comma-separated strings | List of usernames to hide messages from | -| `onlyfrom` or `fromonly` | comma-separated strings | List of usernames to exclusively show | -| `badkarma` | 0.0-1.0 | Filters messages based on sentiment score | -| `showonlymods` | boolean | Shows messages from moderators only | -| `showonlyvips` | boolean | Shows messages from VIPs only | -| `excludefiltered` | boolean | Prevents filtered messages from being auto-featured | +| `hidetwitch` | boolean | Hides Twitch messages | +| `hidefrom` or `exclude` | comma-separated strings | List of usernames to hide messages from | +| `onlyfrom` or `fromonly` | comma-separated strings | List of usernames to exclusively show | +| `badkarma` | 0.0-1.0 | Filters messages based on sentiment score | +| `showonlymods` | boolean | Shows messages from moderators only | +| `showonlyvips` | boolean | Shows messages from VIPs only | +| `excludefiltered` | boolean | Prevents filtered messages from being auto-featured | ### Message Selection & Queue Parameters | Parameter | Values | Description | |-----------|---------|-------------| -| `autoshow` | boolean | Automatically features new messages | -| `autoshowtime` | number | Custom timing for auto-show feature (milliseconds) | -| `chartime` | number | Time per character for auto-show duration | -| `autoshowdonos` | boolean | Auto-features only donation messages | -| `autoshowmembers` | boolean | Auto-features only member messages | -| `autoshowqueued` | boolean | Auto-shows queued messages | -| `autoshowcontentimages` | boolean | Auto-features queued messages that include image/content attachments | -| `queueonly` | boolean | Shows only queued messages | -| `pinnedonly` | boolean | Shows only pinned messages | -| `viewonly` | boolean | Disables chat, pin, and feature capabilities | -| `featuredmode` | boolean | Connects `dock.html` to the featured-message feed so it only receives selected messages | -| `chatmode` | boolean | Enables chat-only mode (no pin/feature) | -| `helpermode` | boolean | Enables view/pin/queue mode (no chat/feature) | -| `chatonly` | boolean | Moves the chat input into the toolbar for a chat-centric layout | -| `openchat` | boolean | Automatically opens the chat composer on load | -| `showmenu` | boolean | Forces the main toolbar to remain visible | -| `sync` or `synced` | boolean | Syncs message selection across multiple docks | -| `autopindonations` | boolean | Auto-pins donation cards as they arrive | -| `autopinquestions` or `autopinquestion` | boolean | Auto-pins cards marked as questions | -| `autoqueuedonations` or `autoqueuedonation` | boolean | Auto-queues donation cards | -| `autoqueuequestions` or `autoqueuequestion` | boolean | Auto-queues question cards | -| `skipdonations` | boolean | Prevents donation cards from being auto-featured | -| `selfqueue` | comma-separated strings | Viewer commands that add themselves to the queue (e.g., `!queue`) | -| `deleteonlylast` | boolean | Only removes the most recent card when clearing messages | -| `disabletimeout` | boolean | Disables the auto-timeout on featured messages | -| `altselect` | boolean | Keeps the Feature button visible when menus are hidden | -| `autoscroll` | boolean | Scrolls to the latest message once and leaves scrolling unlocked | -| `manualscroll` | boolean | Disables automatic near-bottom scrolling unless Force scroll is enabled | -| `buffer` | boolean | Enables adaptive buffering for smoother message pacing | -| `bufferdelay` | number | Base delay (ms) used when buffering messages | -| `buffermin` | number | Minimum delay (ms) used when buffering messages | -| `buffermax` | number | Maximum delay (ms) used when buffering messages | -| `random` | boolean | Randomizes which queued message is featured next | +| `autoshow` | boolean | Automatically features new messages | +| `autoshowtime` | number | Custom timing for auto-show feature (milliseconds) | +| `chartime` | number | Time per character for auto-show duration | +| `autoshowdonos` | boolean | Auto-features only donation messages | +| `autoshowmembers` | boolean | Auto-features only member messages | +| `autoshowqueued` | boolean | Auto-shows queued messages | +| `autoshowcontentimages` | boolean | Auto-features queued messages that include image/content attachments | +| `queueonly` | boolean | Shows only queued messages | +| `pinnedonly` | boolean | Shows only pinned messages | +| `viewonly` | boolean | Disables chat, pin, and feature capabilities | +| `featuredmode` | boolean | Connects `dock.html` to the featured-message feed so it only receives selected messages | +| `chatmode` | boolean | Enables chat-only mode (no pin/feature) | +| `helpermode` | boolean | Enables view/pin/queue mode (no chat/feature) | +| `chatonly` | boolean | Moves the chat input into the toolbar for a chat-centric layout | +| `openchat` | boolean | Automatically opens the chat composer on load | +| `showmenu` | boolean | Forces the main toolbar to remain visible | +| `sync` or `synced` | boolean | Syncs message selection across multiple docks | +| `autopindonations` | boolean | Auto-pins donation cards as they arrive | +| `autopinquestions` or `autopinquestion` | boolean | Auto-pins cards marked as questions | +| `autoqueuedonations` or `autoqueuedonation` | boolean | Auto-queues donation cards | +| `autoqueuequestions` or `autoqueuequestion` | boolean | Auto-queues question cards | +| `skipdonations` | boolean | Prevents donation cards from being auto-featured | +| `selfqueue` | comma-separated strings | Viewer commands that add themselves to the queue (e.g., `!queue`) | +| `deleteonlylast` | boolean | Only removes the most recent card when clearing messages | +| `disabletimeout` | boolean | Disables the auto-timeout on featured messages | +| `altselect` | boolean | Keeps the Feature button visible when menus are hidden | +| `autoscroll` | boolean | Scrolls to the latest message once and leaves scrolling unlocked | +| `manualscroll` | boolean | Disables automatic near-bottom scrolling unless Force scroll is enabled | +| `buffer` | boolean | Enables adaptive buffering for smoother message pacing | +| `bufferdelay` | number | Base delay (ms) used when buffering messages | +| `buffermin` | number | Minimum delay (ms) used when buffering messages | +| `buffermax` | number | Maximum delay (ms) used when buffering messages | +| `random` | boolean | Randomizes which queued message is featured next | ### Text-to-Speech (TTS) Parameters @@ -222,13 +222,13 @@ https://socialstream.ninja/dock.html?session=xxxxxxxxx&urlparameter=value | Parameter | Values | Description | |-----------|---------|-------------| -| `showonlydonos` | boolean | Shows only messages with donations | -| `showonlymembers` | boolean | Shows only messages from members | -| `stripdonations` | boolean | Removes donation data from messages | -| `nodonohighlight` | boolean | Disables background highlighting for donations | -| `autoyoutubememberchat` | boolean | Auto-features YouTube member milestone chat cards | -| `tiktokfans` | boolean | Treats TikTok fans as channel members for highlighting | -| `t1` | number | First donation threshold amount (USD) | +| `showonlydonos` | boolean | Shows only messages with donations | +| `showonlymembers` | boolean | Shows only messages from members | +| `stripdonations` | boolean | Removes donation data from messages | +| `nodonohighlight` | boolean | Disables background highlighting for donations | +| `autoyoutubememberchat` | boolean | Auto-features YouTube member milestone chat cards | +| `tiktokfans` | boolean | Treats TikTok fans as channel members for highlighting | +| `t1` | number | First donation threshold amount (USD) | | `t1c` | hex/color | Color for first donation threshold messages | | `t2` | number | Second donation threshold amount (USD) | | `t2c` | hex/color | Color for second donation threshold messages | @@ -239,7 +239,7 @@ https://socialstream.ninja/dock.html?session=xxxxxxxxx&urlparameter=value | Parameter | Values | Description | |-----------|---------|-------------| -| `myname` or `botlist` or `botnames` | comma-separated strings | List of bot usernames to identify | +| `myname` or `botlist` or `botnames` | comma-separated strings | List of bot usernames to identify | | `hidebots` | boolean | Hides messages from identified bots | | `hidebotnames` | boolean | Hides names of identified bots | | `hidehosts` | boolean | Hides messages from hosts | @@ -256,11 +256,11 @@ https://socialstream.ninja/dock.html?session=xxxxxxxxx&urlparameter=value | Parameter | Values | Description | |-----------|---------|-------------| -| `beep` | boolean | Enables sound notification for new messages | -| `beepvolume` | 0-100 | Sets volume for notification sound (percentage) | -| `custombeep` | URL | Custom sound file URL for notifications | -| `beepwords` | boolean | Replaces asterisks with "beep" in messages | -| `quietcommands` | boolean | Disables the TTS beep when command shortcuts trigger | +| `beep` | boolean | Enables sound notification for new messages | +| `beepvolume` | 0-100 | Sets volume for notification sound (percentage) | +| `custombeep` | URL | Custom sound file URL for notifications | +| `beepwords` | boolean | Replaces asterisks with "beep" in messages | +| `quietcommands` | boolean | Disables the TTS beep when command shortcuts trigger | ### OBS Integration Parameters @@ -269,28 +269,28 @@ https://socialstream.ninja/dock.html?session=xxxxxxxxx&urlparameter=value | `remote` | boolean/string | Enables OBS scene state display | | `cycle` | boolean | Allows guests to change OBS scenes with !cycle | | `startstop` | boolean | Allows privileged users to start/stop OBS | -| `server` | URL | Custom WebSocket server URL | -| `server2` | URL | Secondary WebSocket server URL | -| `server3` | URL | Tertiary WebSocket server URL | -| `lanonly` | boolean | Restricts P2P connections to LAN only | - -### External Automation & Integrations - -| Parameter | Values | Description | -|-----------|---------|-------------| -| `postserver` | URL | Endpoint that receives featured message data via POST | -| `putserver` | URL | Endpoint that receives featured message data via PUT | -| `h2rurl` | URL | Base URL for H2R Graphics API posts | -| `h2r` | string | Path or endpoint suffix appended to `h2rurl` | -| `spxserver` | URL | Base URL for SPX-GC | -| `spxfunction` | string | SPX function invoked when a message is featured | -| `spxlayer` | string | SPX template/layer identifier to update | -| `singular` | string | Singular.live data node ID for webhook updates | -| `passtts` | boolean | Allows the `!pass` shortcut to forward TTS to remote automation | -| `passttsmod` | boolean | Restricts the `!pass` TTS shortcut to moderators | -| `v` | string | Overrides the dock version used for remote compatibility checks | - -### Export & Saving Parameters +| `server` | URL | Custom WebSocket server URL | +| `server2` | URL | Secondary WebSocket server URL | +| `server3` | URL | Tertiary WebSocket server URL | +| `lanonly` | boolean | Restricts P2P connections to LAN only | + +### External Automation & Integrations + +| Parameter | Values | Description | +|-----------|---------|-------------| +| `postserver` | URL | Endpoint that receives featured message data via POST | +| `putserver` | URL | Endpoint that receives featured message data via PUT | +| `h2rurl` | URL | Base URL for H2R Graphics API posts | +| `h2r` | string | Path or endpoint suffix appended to `h2rurl` | +| `spxserver` | URL | Base URL for SPX-GC | +| `spxfunction` | string | SPX function invoked when a message is featured | +| `spxlayer` | string | SPX template/layer identifier to update | +| `singular` | string | Singular.live data node ID for webhook updates | +| `passtts` | boolean | Allows the `!pass` shortcut to forward TTS to remote automation | +| `passttsmod` | boolean | Restricts the `!pass` TTS shortcut to moderators | +| `v` | string | Overrides the dock version used for remote compatibility checks | + +### Export & Saving Parameters | Parameter | Values | Description | |-----------|---------|-------------| @@ -305,46 +305,46 @@ https://socialstream.ninja/dock.html?session=xxxxxxxxx&urlparameter=value | Parameter | Values | Description | |-----------|---------|-------------| -| `ttskey` or `googlettskey` | string | Google Cloud TTS API key | -| `elevenlabskey` | string | ElevenLabs TTS API key | -| `speechifykey` | string | Speechify TTS API key | -| `geminikey` | string | Gemini TTS API key | -| `openaikey` or `customttskey` or `localttskey` | string | OpenAI or custom local TTS endpoint API key. Optional for local endpoints. | - -### OpenAI-Compatible and Custom TTS Parameters - -| Parameter | Values | Description | -|-----------|---------|-------------| -| `ttsprovider` | `openai`, `customtts`, `localtts` | Uses the OpenAI-compatible audio speech request format. `customtts` and `localtts` are aliases for local/self-hosted endpoints. | -| `openaiendpoint` or `customttsendpoint` or `localttsendpoint` | URL | OpenAI-compatible TTS endpoint, such as `http://127.0.0.1:8124/v1/audio/speech` | -| `voiceopenai` or `customttsvoice` or `localttsvoice` | string | Voice name, speaker ID, or cloned voice name accepted by the endpoint | -| `openaicustomvoice` | string | Custom voice value used when the popup voice selector is set to Custom | -| `openaimodel` or `customttsmodel` or `localttsmodel` | string | TTS model name sent in the request body | -| `openaicustommodelx` | string | Custom model value used when the popup model selector is set to Custom | -| `openaispeed` or `customttsspeed` or `localttsspeed` | float | Speaking speed sent to compatible endpoints | -| `openaiformat` or `customttsformat` or `localttsformat` | `mp3`, `wav`, `opus`, `aac`, `flac` | Preferred audio response format | - -### Google Cloud TTS Parameters +| `ttskey` or `googlettskey` | string | Google Cloud TTS API key | +| `elevenlabskey` | string | ElevenLabs TTS API key | +| `speechifykey` | string | Speechify TTS API key | +| `geminikey` | string | Gemini TTS API key | +| `openaikey` or `customttskey` or `localttskey` | string | OpenAI or custom local TTS endpoint API key. Optional for local endpoints. | + +### OpenAI-Compatible and Custom TTS Parameters + +| Parameter | Values | Description | +|-----------|---------|-------------| +| `ttsprovider` | `openai`, `customtts`, `localtts` | Uses the OpenAI-compatible audio speech request format. `customtts` and `localtts` are aliases for local/self-hosted endpoints. | +| `openaiendpoint` or `customttsendpoint` or `localttsendpoint` | URL | OpenAI-compatible TTS endpoint, such as `http://127.0.0.1:8124/v1/audio/speech` | +| `voiceopenai` or `customttsvoice` or `localttsvoice` | string | Voice name, speaker ID, or cloned voice name accepted by the endpoint | +| `openaicustomvoice` | string | Custom voice value used when the popup voice selector is set to Custom | +| `openaimodel` or `customttsmodel` or `localttsmodel` | string | TTS model name sent in the request body | +| `openaicustommodelx` | string | Custom model value used when the popup model selector is set to Custom | +| `openaispeed` or `customttsspeed` or `localttsspeed` | float | Speaking speed sent to compatible endpoints | +| `openaiformat` or `customttsformat` or `localttsformat` | `mp3`, `wav`, `opus`, `aac`, `flac` | Preferred audio response format | + +### Google Cloud TTS Parameters | Parameter | Values | Description | |-----------|---------|-------------| | `googlerate` | float | Google TTS speaking rate | | `googlepitch` | float | Google TTS pitch adjustment | -| `googleaudioprofile` | string | Audio profile (e.g., "handset-class-device") | -| `voicegoogle` | string | Google TTS voice name (e.g., "en-GB-Standard-A") | - -### Gemini TTS Parameters - -| Parameter | Values | Description | -|-----------|---------|-------------| -| `geminimodel` | string | Gemini TTS model (e.g., "gemini-2.5-flash-preview-tts") | -| `voicegemini` | string | Gemini prebuilt voice name (e.g., "Kore") | -| `geminilang` | BCP-47 code | Optional Gemini speech language code (e.g., "th-TH") | -| `geministyle` or `geminiprompt` | string | Gemini-only style instructions prepended to the TTS prompt | - -### ElevenLabs TTS Parameters - -| Parameter | Values | Description | +| `googleaudioprofile` | string | Audio profile (e.g., "handset-class-device") | +| `voicegoogle` | string | Google TTS voice name (e.g., "en-GB-Standard-A") | + +### Gemini TTS Parameters + +| Parameter | Values | Description | +|-----------|---------|-------------| +| `geminimodel` | string | Gemini TTS model (e.g., "gemini-2.5-flash-preview-tts") | +| `voicegemini` | string | Gemini prebuilt voice name (e.g., "Kore") | +| `geminilang` | BCP-47 code | Optional Gemini speech language code (e.g., "th-TH") | +| `geministyle` or `geminiprompt` | string | Gemini-only style instructions prepended to the TTS prompt | + +### ElevenLabs TTS Parameters + +| Parameter | Values | Description | |-----------|---------|-------------| | `elevenlatency` | 0-4 | Latency optimization level | | `elevenstability` | 0.0-1.0 | Voice stability setting | @@ -367,7 +367,7 @@ https://socialstream.ninja/dock.html?session=xxxxxxxxx&urlparameter=value | Parameter | Values | Description | |-----------|---------|-------------| -| `filterevents` | comma-separated strings | Exact event names or text keywords to filter when `data.event` is present | +| `filterevents` | comma-separated strings | Exact event names or text keywords to filter when `data.event` is present | | `trivialevents` | boolean | Allows background shading for minor events | | `showonlyevents` | boolean | Shows only stream events | | `hideallevents` | boolean | Hides all stream events | @@ -391,24 +391,32 @@ https://socialstream.ninja/dock.html?session=xxxxxxxxx&urlparameter=value | `filtertid` | comma-separated numbers | Filter by thread IDs | | `branded` | boolean | Shows channel icon | -## Tip Jar & Goal Meter Parameters (`tipjar.html`) - -| Parameter | Values | Description | -|-----------|--------|-------------| -| `style` | `jar`, `meter`, `minimal` | Selects the tip jar display style | -| `goal` | number | Sets the target amount for the bar or jar | -| `title` | string | Sets the visible goal title | -| `tipjartype` | `usd`, `stars`, `bits`, `coins`, `diamonds`, `kicks`, `jewels`, `tokens`, `hearts`, `gold` | Counts only that donation unit/type. When set, the jar uses the raw unit count instead of converting to USD | -| `tipjarunit` or `donationtype` | same as `tipjartype` | Alias for `tipjartype` | -| `tipjarunitlabel` | string | Overrides the displayed unit label for a filtered unit bar | -| `tipjarsource` | source type such as `facebook`, `youtube`, `twitch`, `kick`, `tiktok`, `stripe`, `kofi`, `bmac`, `fourthwall` | Counts only donations from that source while preserving the normal USD conversion unless `tipjartype` is also set | -| `donationsource` | same as `tipjarsource` | Alias for `tipjarsource` | -| `persistent` | boolean | Keeps the current amount between sessions. Filtered bars use separate saved totals | -| `controls` | boolean | Shows reset/history/export controls | -| `sound` | boolean | Plays a sound on accepted donations | -| `hype` | boolean | Enables hype cup scoring mode | - -## Other options for other overlays. - -WIP. +## Tip Jar & Goal Meter Parameters (`tipjar.html`) + +| Parameter | Values | Description | +|-----------|--------|-------------| +| `style` | `jar`, `meter`, `bar`, `minimal` | Selects the tip jar display style. `bar` is the fluid goal bar | +| `goal` | number | Sets the target amount for the bar or jar | +| `title` | string | Sets the visible goal title (e.g. `Star Goal`, `SuperChat Goal`) | +| `tipjartype` | `usd`, `stars`, `bits`, `coins`, `diamonds`, `kicks`, `jewels`, `tokens`, `hearts`, `gold` | Counts only that donation unit/type. When set, the jar uses the raw unit count instead of converting to USD | +| `tipjarunit` or `donationtype` | same as `tipjartype` | Alias for `tipjartype` | +| `tipjarunitlabel` | string | Overrides the displayed unit label for a filtered unit bar | +| `tipjarsource` | source type such as `facebook`, `youtube`, `twitch`, `kick`, `tiktok`, `stripe`, `kofi`, `bmac`, `fourthwall` | Counts only donations from that source while preserving the normal USD conversion unless `tipjartype` is also set | +| `donationsource` | same as `tipjarsource` | Alias for `tipjarsource` | +| `persistent` | boolean | Keeps the current amount between sessions. Filtered bars use separate saved totals | +| `controls` | boolean | Shows reset/history/export controls | +| `sound` | boolean | Plays a sound on accepted donations | +| `hype` | boolean | Enables hype cup scoring mode | +| `levelsize` or `increment` | number | Turns the goal into repeating bands/levels of this size (e.g. `1000` stars or `50` dollars). The bar fills, celebrates, and rolls into the next level instead of stopping | +| `fillstart` or `barcolorstart` | CSS color | Fill color for the `bar` style when empty/low (default `#2196F3` blue). Also recolors the `meter` fill | +| `fillend` or `barcolorend` | CSS color | Fill color for the `bar` style when full (default `#f44336` red). Also recolors the `meter` fill | +| `fillmode` | `progress`, `gradient`, `solid` | `bar` fill behavior. `progress` (default) shifts the whole bar from start→end color as it fills; `gradient` reveals a fixed start→end gradient; `solid` uses only the start color | +| `barheight` | number | Height of the fluid goal bar in pixels (default `64`) | +| `noliquid` | boolean | Disables the flowing-liquid animation on the `bar` style | +| `theme` | `default`, `neon`, `gold` | Visual theme for the meter/bar | +| `celebration` | `hearts`, `confetti`, `fireworks`, `none` | Effect played on milestones/level-ups | + +## Other options for other overlays. + +WIP. diff --git a/popup.html b/popup.html index 4d2539efd..62bd6f5f4 100644 --- a/popup.html +++ b/popup.html @@ -10751,6 +10751,7 @@

Style and Theme

@@ -10812,6 +10813,28 @@

Goal Settings

+ +

Goal Bar Style

+
+ + +
+
+ + +
+
+ + +
+
+ + +
diff --git a/tipjar.html b/tipjar.html index 2ce3ff276..beb4a0dc2 100644 --- a/tipjar.html +++ b/tipjar.html @@ -6,8 +6,8 @@ Tip Jar Overlay - Social Stream Ninja - - + +
- - Cup Overlay -
$0 / $250
-
-
-
+ + Cup Overlay +
$0 / $250
+
+
+
@@ -401,11 +515,26 @@

Stream Goal

-
$0.00
-
of $250 goal
-
0%
-
-
+
$0.00
+
of $250 goal
+
0%
+
+ + + +
+
+

Stream Goal

+
+
+
$0 / $250
+
+
+ + 0% +
+
+
@@ -435,40 +564,51 @@

🏆 Top Dono - From 986069bc05a60af4c5170639ddec6a854c3a1566 Mon Sep 17 00:00:00 2001 From: steveseguin Date: Sun, 21 Jun 2026 22:59:07 -0400 Subject: [PATCH 04/30] fix(tipjar): correct level rollover using timed completion state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Introduce `levelRolloverTimer` and `levelCompletionState` to display a completed level briefly before rolling over. - Modify `updateAmount()` to clear level state on non‑positive amounts or when the level hasn’t advanced, ensuring rollover only triggers on actual level changes. - Update `resetTipJarAmount()` to call `clearLevelCompletionState()`, so manual resets properly clear any pending rollover display. - Refine `renderAmount()` and `getProgressState()` to check for the completion state, enabling the brief “level complete” visual before returning to normal progress. [auto-enhanced] --- tipjar.html | 140 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 90 insertions(+), 50 deletions(-) diff --git a/tipjar.html b/tipjar.html index beb4a0dc2..e994a99e5 100644 --- a/tipjar.html +++ b/tipjar.html @@ -671,13 +671,15 @@

🏆 Top Dono const amountStorageKey = (hypeMode ? 'tipjar_hype_amount' : 'tipjar_amount') + storageSuffix; const historyStorageKey = (hypeMode ? 'tipjar_hype_history' : 'tipjar_history') + storageSuffix; const completionsStorageKey = 'tipjar_hype_completions' + storageSuffix; - let currentAmount = persistent ? (parseFloat(localStorage.getItem(amountStorageKey)) || 0) : 0; - let completionCount = persistent ? (parseInt(localStorage.getItem(completionsStorageKey) || '0', 10) || 0) : 0; - let completionResetTimer = null; - const recentTips = []; - const maxRecentTips = 5; - const donationHistory = persistent ? (JSON.parse(localStorage.getItem(historyStorageKey) || '[]')) : []; - const processedContributions = {}; + let currentAmount = persistent ? (parseFloat(localStorage.getItem(amountStorageKey)) || 0) : 0; + let completionCount = persistent ? (parseInt(localStorage.getItem(completionsStorageKey) || '0', 10) || 0) : 0; + let completionResetTimer = null; + let levelRolloverTimer = null; + let levelCompletionState = null; + const recentTips = []; + const maxRecentTips = 5; + const donationHistory = persistent ? (JSON.parse(localStorage.getItem(historyStorageKey) || '[]')) : []; + const processedContributions = {}; // Socket server variables let socketserver = null; @@ -823,16 +825,17 @@

🏆 Top Dono }); } - function resetTipJarAmount(showNotice) { - if (completionResetTimer) { - clearTimeout(completionResetTimer); - completionResetTimer = null; - } - currentAmount = 0; - if (hypeMode) { - completionCount = 0; - if (persistent) { - localStorage.setItem(completionsStorageKey, completionCount.toString()); + function resetTipJarAmount(showNotice) { + if (completionResetTimer) { + clearTimeout(completionResetTimer); + completionResetTimer = null; + } + clearLevelCompletionState(); + currentAmount = 0; + if (hypeMode) { + completionCount = 0; + if (persistent) { + localStorage.setItem(completionsStorageKey, completionCount.toString()); } } renderAmount(); @@ -848,16 +851,43 @@

🏆 Top Dono return command === 'resettipjar' || command === 'reset_tipjar' || command === 'tipjar_reset'; } - function saveAmount() { - if (persistent) { - localStorage.setItem(amountStorageKey, currentAmount.toString()); - } - } - - function renderAmount() { - saveAmount(); - const state = getProgressState(); - const percentage = state.percentage; + function saveAmount() { + if (persistent) { + localStorage.setItem(amountStorageKey, currentAmount.toString()); + } + } + + function clearLevelCompletionState() { + if (levelRolloverTimer) { + clearTimeout(levelRolloverTimer); + levelRolloverTimer = null; + } + levelCompletionState = null; + } + + function showCompletedLevel(completedLevel) { + clearLevelCompletionState(); + levelCompletionState = { + isLevel: true, + level: completedLevel, + completed: completedLevel, + current: levelSize, + goal: levelSize, + total: currentAmount, + percentage: 100 + }; + renderAmount(); + levelRolloverTimer = setTimeout(function() { + levelRolloverTimer = null; + levelCompletionState = null; + renderAmount(); + }, completionDelayMs); + } + + function renderAmount() { + saveAmount(); + const state = getProgressState(); + const percentage = state.percentage; // Update different styles if (style === 'jar') { @@ -878,24 +908,33 @@

🏆 Top Dono updateCompletionDisplay(); } - function updateAmount(amount) { - const previousAmount = currentAmount; - currentAmount += amount; - renderAmount(); - - if (amount <= 0) return; - - // Recurring level mode: celebrate whenever a new increment band is filled. - if (levelSize > 0) { - const previousLevel = Math.floor(previousAmount / levelSize); - const newLevel = Math.floor(currentAmount / levelSize); - if (newLevel > previousLevel) { - triggerLevelUp(newLevel); - } - return; - } - - if (goal <= 0) return; + function updateAmount(amount) { + const previousAmount = currentAmount; + currentAmount += amount; + + if (amount <= 0) { + clearLevelCompletionState(); + renderAmount(); + return; + } + + // Recurring level mode: celebrate whenever a new increment band is filled. + if (levelSize > 0) { + const previousLevel = Math.floor(previousAmount / levelSize); + const newLevel = Math.floor(currentAmount / levelSize); + if (newLevel > previousLevel) { + showCompletedLevel(newLevel); + triggerLevelUp(newLevel); + } else { + clearLevelCompletionState(); + renderAmount(); + } + return; + } + + renderAmount(); + + if (goal <= 0) return; if (previousAmount < goal * 0.25 && currentAmount >= goal * 0.25) triggerMilestone(25); if (previousAmount < goal * 0.50 && currentAmount >= goal * 0.50) triggerMilestone(50); @@ -1179,11 +1218,12 @@

🏆 Top Dono return `$${forceCents ? num.toFixed(2) : formatNumber(num)}`; } - function getProgressState() { - if (levelSize > 0) { - const completed = Math.floor(currentAmount / levelSize); - const within = currentAmount - (completed * levelSize); - return { + function getProgressState() { + if (levelSize > 0) { + if (levelCompletionState) return levelCompletionState; + const completed = Math.floor(currentAmount / levelSize); + const within = currentAmount - (completed * levelSize); + return { isLevel: true, level: completed + 1, completed: completed, From 5df1909a2ae626b8dc56c001c280052b5035ef7a Mon Sep 17 00:00:00 2001 From: steveseguin Date: Sun, 21 Jun 2026 23:32:34 -0400 Subject: [PATCH 05/30] feat(tipjar): add compact/vertical/text styles and test donation buttons Extend tipjar with three new display styles (compact bar, vertical bar, text-only) and a test donation panel that sends simulated platform donations (Facebook Stars, YouTube SuperChat, Twitch Bits, TikTok Hearts) directly from the popup. Reorganize tipjar options into separate collapsible sections (General Controls, Hype Cup Scoring, Style/Goal/Filters, Test Donations) for better UX. Update parameters.md with the new style options and the `barradius` parameter, and add corresponding UI elements in popup.html and popup.js. [auto-enhanced] --- parameters.md | 9 +- popup.html | 60 +++++++- popup.js | 72 ++++++++++ tipjar.html | 380 ++++++++++++++++++++++++++++++++++++++------------ 4 files changed, 418 insertions(+), 103 deletions(-) diff --git a/parameters.md b/parameters.md index 6b305893e..26cadc1ac 100644 --- a/parameters.md +++ b/parameters.md @@ -395,7 +395,7 @@ https://socialstream.ninja/dock.html?session=xxxxxxxxx&urlparameter=value | Parameter | Values | Description | |-----------|--------|-------------| -| `style` | `jar`, `meter`, `bar`, `minimal` | Selects the tip jar display style. `bar` is the fluid goal bar | +| `style` | `jar`, `meter`, `bar`, `compact`, `vertical`, `minimal`, `text` | Selects the tip jar display style. `bar` is the fluid goal bar; `compact`/`vertical` are simple square-edged bars for corners; `text` is a one-line readout | | `goal` | number | Sets the target amount for the bar or jar | | `title` | string | Sets the visible goal title (e.g. `Star Goal`, `SuperChat Goal`) | | `tipjartype` | `usd`, `stars`, `bits`, `coins`, `diamonds`, `kicks`, `jewels`, `tokens`, `hearts`, `gold` | Counts only that donation unit/type. When set, the jar uses the raw unit count instead of converting to USD | @@ -408,10 +408,11 @@ https://socialstream.ninja/dock.html?session=xxxxxxxxx&urlparameter=value | `sound` | boolean | Plays a sound on accepted donations | | `hype` | boolean | Enables hype cup scoring mode | | `levelsize` or `increment` | number | Turns the goal into repeating bands/levels of this size (e.g. `1000` stars or `50` dollars). The bar fills, celebrates, and rolls into the next level instead of stopping | -| `fillstart` or `barcolorstart` | CSS color | Fill color for the `bar` style when empty/low (default `#2196F3` blue). Also recolors the `meter` fill | -| `fillend` or `barcolorend` | CSS color | Fill color for the `bar` style when full (default `#f44336` red). Also recolors the `meter` fill | +| `fillstart` or `barcolorstart` | CSS color | Fill color when empty/low (default `#2196F3` blue). Applies to `bar`/`compact`/`vertical`, and recolors the `meter` fill | +| `fillend` or `barcolorend` | CSS color | Fill color when full (default `#f44336` red). Applies to `bar`/`compact`/`vertical`, and recolors the `meter` fill | | `fillmode` | `progress`, `gradient`, `solid` | `bar` fill behavior. `progress` (default) shifts the whole bar from start→end color as it fills; `gradient` reveals a fixed start→end gradient; `solid` uses only the start color | -| `barheight` | number | Height of the fluid goal bar in pixels (default `64`) | +| `barheight` | number | Track height (px) for `bar`/`compact`/`vertical` styles | +| `barradius` | number or CSS length | Corner radius for bar tracks. Use `0` for square corner-overlay edges | | `noliquid` | boolean | Disables the flowing-liquid animation on the `bar` style | | `theme` | `default`, `neon`, `gold` | Visual theme for the meter/bar | | `celebration` | `hearts`, `confetti`, `fireworks`, `none` | Effect played on milestones/level-ups | diff --git a/popup.html b/popup.html index 62bd6f5f4..88623256b 100644 --- a/popup.html +++ b/popup.html @@ -10656,11 +10656,11 @@

- +
-

General Options

+

🔧 General Options

-

Hype Cup Options

+
+
+
+
+
+
+
+ + +
+
+
+

🏆 Hype Cup Options

-

Style and Theme

+
+
+
+
+
+
+
+ + +
+
+
+

🎨 Style and Theme

@@ -10773,7 +10800,7 @@

Style and Theme

-

Goal Settings

+

🎯 Goal Settings

@@ -10814,7 +10841,7 @@

Goal Settings

-

Goal Bar Style

+

📊 Goal Bar Style

@@ -10840,6 +10867,27 @@

Goal Bar Style

+ +
+
+
+
+
+
+
+ + +
+
+
+

Test Donations

+
+ + + + +
+ Sends a fake donation to connected overlays.
diff --git a/popup.js b/popup.js index fbce9c634..f1bd9c1fb 100644 --- a/popup.js +++ b/popup.js @@ -6953,6 +6953,77 @@ function buildTestAlertPayload(category, overrides = {}) { }; } +function buildTipJarTestDonationPayload(kind) { + const payloads = { + 'facebook-stars': { + type: 'facebook', + platform: 'facebook', + chatname: 'Star Supporter', + chatmessage: 'Testing Facebook Stars', + hasDonation: '500 Stars', + donoValue: 5, + chatimg: createPreviewAvatarDataUri('FB', '#1877f2') + }, + 'youtube-superchat': { + type: 'youtube', + platform: 'youtube', + event: 'donation', + chatname: 'SuperChat Fan', + chatmessage: 'Testing a Super Chat donation', + hasDonation: '$10.00', + donoValue: 10, + chatimg: createPreviewAvatarDataUri('YT', '#ff0033') + }, + 'twitch-bits': { + type: 'twitch', + platform: 'twitch', + event: 'cheer', + chatname: 'Bits Tester', + chatmessage: 'Testing Twitch bits', + hasDonation: '500 bits', + donoValue: 5, + chatimg: createPreviewAvatarDataUri('TW', '#9146ff'), + meta: { bits: 500 } + }, + 'tiktok-hearts': { + type: 'tiktok', + platform: 'tiktok', + event: 'gift', + chatname: 'Heart Sender', + chatmessage: 'Testing TikTok hearts', + hasDonation: '100 hearts', + donoValue: 1, + chatimg: createPreviewAvatarDataUri('TT', '#fe2c55'), + meta: { giftName: 'Hearts', giftCount: 100 } + } + }; + + const payload = payloads[kind]; + if (!payload) { + return null; + } + + return { + ...payload, + id: nextOverlayPreviewId('tipjar_test'), + timestamp: Date.now() + }; +} + +function attachTipJarTestDonationButtons() { + document.querySelectorAll('[data-tipjar-test]').forEach(function(button) { + button.addEventListener('click', function() { + const payload = buildTipJarTestDonationPayload(button.getAttribute('data-tipjar-test')); + if (!payload) { + return; + } + chrome.runtime.sendMessage({ cmd: 'testAlert', payload }, function() { + log('ignore callback for this action'); + }); + }); + }); +} + function attachOverlayPreviewControls(previewKey, buttonConfigs = []) { const config = overlayPreviewConfigs[previewKey]; if (!config) { @@ -8947,6 +9018,7 @@ document.addEventListener("DOMContentLoaded", async function(event) { { id: 'multi-alert-preview-hype', descriptor: () => buildMultiAlertPreviewDescriptor('hype') }, { id: 'multi-alert-preview-clear', descriptor: false } ]); + attachTipJarTestDonationButtons(); var previewPlatformSelect = document.getElementById('multi-alert-preview-platform'); if (previewPlatformSelect) { diff --git a/tipjar.html b/tipjar.html index e994a99e5..4b825e31b 100644 --- a/tipjar.html +++ b/tipjar.html @@ -480,6 +480,118 @@ border-color: var(--primary-color); box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.7), 0 0 26px var(--primary-color); } + + /* Compact Bar Style (square edges, corner-friendly) */ + #compact-style { + width: 100%; + max-width: 460px; + padding: 12px; + } + + .compact-container { width: 100%; } + + .compact-header { + display: flex; + justify-content: space-between; + align-items: baseline; + color: #fff; + font-size: 16px; + font-weight: 700; + margin-bottom: 6px; + text-shadow: 0 1px 3px rgba(0, 0, 0, 0.85); + } + + .compact-header .compact-amount { font-variant-numeric: tabular-nums; } + + .compact-track { + position: relative; + width: 100%; + height: 22px; + background: rgba(0, 0, 0, 0.6); + border: 1px solid rgba(255, 255, 255, 0.18); + border-radius: 3px; + overflow: hidden; + } + + .compact-fill { + position: absolute; + top: 0; + left: 0; + bottom: 0; + width: 0%; + background-color: #2196F3; + transition: width 0.6s ease, background-color 0.6s ease; + } + + /* Vertical Bar Style (thermometer, square edges) */ + #vertical-style { + width: 100%; + height: 100%; + padding: 20px; + } + + .vertical-container { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + } + + .vertical-title { + color: #fff; + font-size: 18px; + font-weight: 700; + margin-bottom: 10px; + text-align: center; + text-shadow: 0 1px 4px rgba(0, 0, 0, 0.85); + } + + .vertical-track { + position: relative; + width: 70px; + height: 320px; + max-height: 70vh; + background: rgba(0, 0, 0, 0.6); + border: 1px solid rgba(255, 255, 255, 0.18); + border-radius: 4px; + overflow: hidden; + } + + .vertical-fill { + position: absolute; + left: 0; + right: 0; + bottom: 0; + height: 0%; + background-color: #2196F3; + transition: height 0.8s ease, background-color 0.8s ease; + } + + .vertical-text { + margin-top: 10px; + color: #fff; + font-size: 16px; + font-weight: 700; + text-align: center; + text-shadow: 0 1px 4px rgba(0, 0, 0, 0.85); + } + + /* Text Only Style (minimal one-liner) */ + #text-style { + width: 100%; + padding: 14px; + } + + .text-line { + color: #fff; + font-size: 26px; + font-weight: 800; + white-space: nowrap; + text-align: center; + text-shadow: 0 2px 6px rgba(0, 0, 0, 0.85); + } @@ -536,6 +648,35 @@

Stream Goal

+ +
+
+
+ Stream Goal + $0 / $250 +
+
+
+
+
+
+ + +
+
+
Stream Goal
+
+
+
+
$0 / $250
+
+
+ + +
+
Stream Goal: $0 / $250
+
+
@@ -605,6 +746,7 @@

🏆 Top Dono const hasCustomFill = urlParams.has('fillstart') || urlParams.has('fillend') || urlParams.has('barcolorstart') || urlParams.has('barcolorend'); const barLiquid = !urlParams.has('noliquid'); const barHeight = readNumberParam('barheight', 0, 1); + const barRadius = urlParams.get('barradius'); // "0" for square edges, "12" for rounded, etc. const levelSize = readNumberParam('levelsize', readNumberParam('increment', 0, 0.0001), 0.0001); const fillStartRgb = parseColorToRgb(fillStartColor, [33, 150, 243]); const fillEndRgb = parseColorToRgb(fillEndColor, [244, 67, 54]); @@ -634,7 +776,15 @@

🏆 Top Dono container.classList.remove('active'); }); document.getElementById(`${style}-style`)?.classList.add('active'); - + + // Optional corner-friendly square (or custom) edges for any bar-based style. + if (barRadius !== null && barRadius !== '') { + const radiusValue = /^\d+(\.\d+)?$/.test(barRadius) ? barRadius + 'px' : barRadius; + document.querySelectorAll('.fluid-bar-track, .compact-track, .vertical-track').forEach(function(el) { + el.style.borderRadius = radiusValue; + }); + } + // Apply custom jar image if provided if (customJarUrl && style === 'jar') { document.getElementById('cup-overlay').src = customJarUrl; @@ -664,6 +814,16 @@

🏆 Top Dono if (!barLiquid) { document.body.classList.add('bar-static'); } + } else if (style === 'compact') { + if (barHeight > 0) { + const track = document.querySelector('.compact-track'); + if (track) track.style.height = barHeight + 'px'; + } + } else if (style === 'vertical') { + if (barHeight > 0) { + const track = document.querySelector('.vertical-track'); + if (track) track.style.height = barHeight + 'px'; + } } // Tracking variables @@ -671,15 +831,15 @@

🏆 Top Dono const amountStorageKey = (hypeMode ? 'tipjar_hype_amount' : 'tipjar_amount') + storageSuffix; const historyStorageKey = (hypeMode ? 'tipjar_hype_history' : 'tipjar_history') + storageSuffix; const completionsStorageKey = 'tipjar_hype_completions' + storageSuffix; - let currentAmount = persistent ? (parseFloat(localStorage.getItem(amountStorageKey)) || 0) : 0; - let completionCount = persistent ? (parseInt(localStorage.getItem(completionsStorageKey) || '0', 10) || 0) : 0; - let completionResetTimer = null; - let levelRolloverTimer = null; - let levelCompletionState = null; - const recentTips = []; - const maxRecentTips = 5; - const donationHistory = persistent ? (JSON.parse(localStorage.getItem(historyStorageKey) || '[]')) : []; - const processedContributions = {}; + let currentAmount = persistent ? (parseFloat(localStorage.getItem(amountStorageKey)) || 0) : 0; + let completionCount = persistent ? (parseInt(localStorage.getItem(completionsStorageKey) || '0', 10) || 0) : 0; + let completionResetTimer = null; + let levelRolloverTimer = null; + let levelCompletionState = null; + const recentTips = []; + const maxRecentTips = 5; + const donationHistory = persistent ? (JSON.parse(localStorage.getItem(historyStorageKey) || '[]')) : []; + const processedContributions = {}; // Socket server variables let socketserver = null; @@ -825,17 +985,17 @@

🏆 Top Dono }); } - function resetTipJarAmount(showNotice) { - if (completionResetTimer) { - clearTimeout(completionResetTimer); - completionResetTimer = null; - } - clearLevelCompletionState(); - currentAmount = 0; - if (hypeMode) { - completionCount = 0; - if (persistent) { - localStorage.setItem(completionsStorageKey, completionCount.toString()); + function resetTipJarAmount(showNotice) { + if (completionResetTimer) { + clearTimeout(completionResetTimer); + completionResetTimer = null; + } + clearLevelCompletionState(); + currentAmount = 0; + if (hypeMode) { + completionCount = 0; + if (persistent) { + localStorage.setItem(completionsStorageKey, completionCount.toString()); } } renderAmount(); @@ -851,43 +1011,43 @@

🏆 Top Dono return command === 'resettipjar' || command === 'reset_tipjar' || command === 'tipjar_reset'; } - function saveAmount() { - if (persistent) { - localStorage.setItem(amountStorageKey, currentAmount.toString()); - } - } - - function clearLevelCompletionState() { - if (levelRolloverTimer) { - clearTimeout(levelRolloverTimer); - levelRolloverTimer = null; - } - levelCompletionState = null; - } - - function showCompletedLevel(completedLevel) { - clearLevelCompletionState(); - levelCompletionState = { - isLevel: true, - level: completedLevel, - completed: completedLevel, - current: levelSize, - goal: levelSize, - total: currentAmount, - percentage: 100 - }; - renderAmount(); - levelRolloverTimer = setTimeout(function() { - levelRolloverTimer = null; - levelCompletionState = null; - renderAmount(); - }, completionDelayMs); - } - - function renderAmount() { - saveAmount(); - const state = getProgressState(); - const percentage = state.percentage; + function saveAmount() { + if (persistent) { + localStorage.setItem(amountStorageKey, currentAmount.toString()); + } + } + + function clearLevelCompletionState() { + if (levelRolloverTimer) { + clearTimeout(levelRolloverTimer); + levelRolloverTimer = null; + } + levelCompletionState = null; + } + + function showCompletedLevel(completedLevel) { + clearLevelCompletionState(); + levelCompletionState = { + isLevel: true, + level: completedLevel, + completed: completedLevel, + current: levelSize, + goal: levelSize, + total: currentAmount, + percentage: 100 + }; + renderAmount(); + levelRolloverTimer = setTimeout(function() { + levelRolloverTimer = null; + levelCompletionState = null; + renderAmount(); + }, completionDelayMs); + } + + function renderAmount() { + saveAmount(); + const state = getProgressState(); + const percentage = state.percentage; // Update different styles if (style === 'jar') { @@ -903,38 +1063,64 @@

🏆 Top Dono if (minimalGoalElement) minimalGoalElement.textContent = formatGoalValue(state.goal); } else if (style === 'bar') { renderBar(state); + } else if (style === 'compact') { + const t = Math.max(0, Math.min(1, percentage / 100)); + const fill = document.getElementById('compact-fill'); + if (fill) { + fill.style.width = percentage + '%'; + applyFillColor(fill, t); + } + setElText('compact-title', state.isLevel ? `${customTitle} (Lvl ${state.level})` : customTitle); + setElText('compact-amount', `${formatProgressPair(state)} · ${Math.round(percentage)}%`); + } else if (style === 'vertical') { + const t = Math.max(0, Math.min(1, percentage / 100)); + const fill = document.getElementById('vertical-fill'); + if (fill) { + fill.style.height = percentage + '%'; + applyFillColor(fill, t); + } + setElText('vertical-title', state.isLevel ? `${customTitle} (Lvl ${state.level})` : customTitle); + setElText('vertical-text', `${formatProgressPair(state)} · ${Math.round(percentage)}%`); + } else if (style === 'text') { + const title = state.isLevel ? `${customTitle} (Lvl ${state.level})` : customTitle; + setElText('text-line', `${title}: ${formatProgressPair(state)} (${Math.round(percentage)}%)`); } updateCompletionDisplay(); } - function updateAmount(amount) { - const previousAmount = currentAmount; - currentAmount += amount; - - if (amount <= 0) { - clearLevelCompletionState(); - renderAmount(); - return; - } - - // Recurring level mode: celebrate whenever a new increment band is filled. - if (levelSize > 0) { - const previousLevel = Math.floor(previousAmount / levelSize); - const newLevel = Math.floor(currentAmount / levelSize); - if (newLevel > previousLevel) { - showCompletedLevel(newLevel); - triggerLevelUp(newLevel); - } else { - clearLevelCompletionState(); - renderAmount(); - } - return; - } - - renderAmount(); - - if (goal <= 0) return; + function applyFillColor(fillEl, t) { + if (!fillEl) return; + fillEl.style.backgroundColor = (fillMode === 'solid') ? fillStartColor : lerpColor(fillStartRgb, fillEndRgb, t); + } + + function updateAmount(amount) { + const previousAmount = currentAmount; + currentAmount += amount; + + if (amount <= 0) { + clearLevelCompletionState(); + renderAmount(); + return; + } + + // Recurring level mode: celebrate whenever a new increment band is filled. + if (levelSize > 0) { + const previousLevel = Math.floor(previousAmount / levelSize); + const newLevel = Math.floor(currentAmount / levelSize); + if (newLevel > previousLevel) { + showCompletedLevel(newLevel); + triggerLevelUp(newLevel); + } else { + clearLevelCompletionState(); + renderAmount(); + } + return; + } + + renderAmount(); + + if (goal <= 0) return; if (previousAmount < goal * 0.25 && currentAmount >= goal * 0.25) triggerMilestone(25); if (previousAmount < goal * 0.50 && currentAmount >= goal * 0.50) triggerMilestone(50); @@ -1063,9 +1249,17 @@

🏆 Top Dono return String(value || '').trim().toLowerCase(); } + function normalizeTipJarSourceValue(value) { + const source = normalizeFilterValue(value).replace(/[\s_-]+/g, ''); + if (source === 'youtubeshort' || source === 'youtubeshorts') { + return 'youtube'; + } + return normalizeFilterValue(value); + } + function normalizeFilterList(value) { return String(value || '').split(',').map(function(item) { - return normalizeFilterValue(item); + return normalizeTipJarSourceValue(item); }).filter(function(item) { return item && item !== 'all' && item !== 'any'; }); @@ -1189,7 +1383,7 @@

🏆 Top Dono function passesTipJarSourceFilter(data) { if (!sourceTypeFilter.length) return true; const meta = getMeta(data); - const source = normalizeFilterValue(data.type || data.platform || meta.source || ''); + const source = normalizeTipJarSourceValue(data.type || data.platform || meta.source || ''); return sourceTypeFilter.indexOf(source) !== -1; } @@ -1218,12 +1412,12 @@

🏆 Top Dono return `$${forceCents ? num.toFixed(2) : formatNumber(num)}`; } - function getProgressState() { - if (levelSize > 0) { - if (levelCompletionState) return levelCompletionState; - const completed = Math.floor(currentAmount / levelSize); - const within = currentAmount - (completed * levelSize); - return { + function getProgressState() { + if (levelSize > 0) { + if (levelCompletionState) return levelCompletionState; + const completed = Math.floor(currentAmount / levelSize); + const within = currentAmount - (completed * levelSize); + return { isLevel: true, level: completed + 1, completed: completed, From 2fe174daf37e967b04e6d216dc09da70096d9578 Mon Sep 17 00:00:00 2001 From: steveseguin Date: Mon, 22 Jun 2026 00:04:33 -0400 Subject: [PATCH 06/30] feat(tipjar): add bar-only display option for compact progress bar Add a new UI toggle and corresponding logic to display only the progress bar with the text embedded inside, hiding the title and meta sections. This provides a more compact visualization suitable for limited-space overlays. - popup.html: add "Only show the bar, with text inside" checkbox mapped to the `baronly` parameter - tipjar.html: apply `bar-only` CSS class to hide title/meta, adjust text rendering to include the title and progress within the bar fill [auto-enhanced] --- popup.html | 13 +++++++++--- tipjar.html | 57 +++++++++++++++++++++++++++++++++-------------------- 2 files changed, 46 insertions(+), 24 deletions(-) diff --git a/popup.html b/popup.html index 88623256b..9653822bc 100644 --- a/popup.html +++ b/popup.html @@ -10656,7 +10656,7 @@

- +
@@ -10703,7 +10703,7 @@

🔧 General Options

- +
@@ -10765,7 +10765,7 @@

🏆 Hype Cup Options

- +
@@ -10862,6 +10862,13 @@

📊 Goal Bar Style

+
+ + Only show the bar, with text inside +
diff --git a/tipjar.html b/tipjar.html index 4b825e31b..0ee06816e 100644 --- a/tipjar.html +++ b/tipjar.html @@ -445,11 +445,20 @@ pointer-events: none; } - body.bar-static .fluid-bar-fill::after { animation: none; } - - @keyframes fluidFlow { - 0% { transform: translateX(-38px); } - 100% { transform: translateX(0); } + body.bar-static .fluid-bar-fill::after { animation: none; } + + body.bar-only #bar-style { + padding: 0; + } + + body.bar-only .fluid-bar-title, + body.bar-only .fluid-bar-meta { + display: none; + } + + @keyframes fluidFlow { + 0% { transform: translateX(-38px); } + 100% { transform: translateX(0); } } .fluid-bar-text { @@ -744,12 +753,13 @@

🏆 Top Dono const fillEndColor = urlParams.get('fillend') || urlParams.get('barcolorend') || '#f44336'; const fillMode = (urlParams.get('fillmode') || 'progress').toLowerCase(); // progress | gradient | solid const hasCustomFill = urlParams.has('fillstart') || urlParams.has('fillend') || urlParams.has('barcolorstart') || urlParams.has('barcolorend'); - const barLiquid = !urlParams.has('noliquid'); - const barHeight = readNumberParam('barheight', 0, 1); - const barRadius = urlParams.get('barradius'); // "0" for square edges, "12" for rounded, etc. - const levelSize = readNumberParam('levelsize', readNumberParam('increment', 0, 0.0001), 0.0001); - const fillStartRgb = parseColorToRgb(fillStartColor, [33, 150, 243]); - const fillEndRgb = parseColorToRgb(fillEndColor, [244, 67, 54]); + const barLiquid = !urlParams.has('noliquid'); + const barHeight = readNumberParam('barheight', 0, 1); + const barRadius = urlParams.get('barradius'); // "0" for square edges, "12" for rounded, etc. + const barOnly = urlParams.has('baronly'); + const levelSize = readNumberParam('levelsize', readNumberParam('increment', 0, 0.0001), 0.0001); + const fillStartRgb = parseColorToRgb(fillStartColor, [33, 150, 243]); + const fillEndRgb = parseColorToRgb(fillEndColor, [244, 67, 54]); // Socket server parameters const hasServerParam = urlParams.has('server') || urlParams.has('server2'); @@ -767,9 +777,13 @@

🏆 Top Dono document.body.classList.add('hype-mode'); } - if (alignRight) { - document.body.classList.add('align-right'); - } + if (alignRight) { + document.body.classList.add('align-right'); + } + + if (barOnly) { + document.body.classList.add('bar-only'); + } // Initialize style document.querySelectorAll('.style-container').forEach(container => { @@ -1498,9 +1512,9 @@

🏆 Top Dono return `rgb(${r}, ${g}, ${bl})`; } - function renderBar(state) { - const fill = document.getElementById('bar-fill'); - if (!fill) return; + function renderBar(state) { + const fill = document.getElementById('bar-fill'); + if (!fill) return; const pct = state.percentage; const t = Math.max(0, Math.min(1, pct / 100)); @@ -1524,10 +1538,11 @@

🏆 Top Dono const glow = lerpColor(fillStartRgb, fillEndRgb, t); fill.style.boxShadow = `0 0 ${Math.round(14 + 18 * t)}px ${glow}`; - setElText('bar-text', formatProgressPair(state)); - setElText('bar-title', state.isLevel ? `${customTitle} — Level ${state.level}` : customTitle); - setElText('bar-level', state.isLevel ? `Level ${state.level} · ${formatGoalValue(state.total, true)} total` : ''); - setElText('bar-percent', `${Math.round(pct)}%`); + const barText = barOnly ? `${customTitle}: ${formatProgressPair(state)}` : formatProgressPair(state); + setElText('bar-text', barText); + setElText('bar-title', state.isLevel ? `${customTitle} — Level ${state.level}` : customTitle); + setElText('bar-level', state.isLevel ? `Level ${state.level} · ${formatGoalValue(state.total, true)} total` : ''); + setElText('bar-percent', `${Math.round(pct)}%`); } function parseDonationString(rawDonation) { From 660b4369a3b26308dc71735cdefdebd652690172 Mon Sep 17 00:00:00 2001 From: steveseguin Date: Mon, 22 Jun 2026 09:42:23 -0400 Subject: [PATCH 07/30] fix(tipjar): normalize 'cash' donation type filter to 'usd' - Add normalizeDonationTypeFilter() to convert 'cash' to 'usd' - Update nativeUnitMode to only enable if filter is not 'usd' - Use normalized filter in donationMatchesTypeFilter() - Append test tube emoji to 'Test Donations' label in popup.html [auto-enhanced] --- popup.html | 2 +- tipjar.html | 33 +++++++++++++++++++-------------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/popup.html b/popup.html index 9653822bc..f8f38c5b0 100644 --- a/popup.html +++ b/popup.html @@ -10883,7 +10883,7 @@

📊 Goal Bar Style

- +
diff --git a/tipjar.html b/tipjar.html index 0ee06816e..082ef100f 100644 --- a/tipjar.html +++ b/tipjar.html @@ -743,10 +743,10 @@

🏆 Top Dono const showCompletions = hypeMode && !urlParams.has('hidecompletions'); const completionDelayMs = readNumberParam('completiondelay', 3000, 0); const dedupeWindowMs = readNumberParam('dedupewindow', 8, 0) * 1000; - const donationTypeFilter = normalizeFilterValue(urlParams.get('tipjartype') || urlParams.get('tipjarunit') || urlParams.get('donationtype') || ''); - const sourceTypeFilter = normalizeFilterList(urlParams.get('tipjarsource') || urlParams.get('donationsource') || ''); - const nativeUnitMode = !!donationTypeFilter; - const nativeUnitLabel = urlParams.get('tipjarunitlabel') || getDonationTypeLabel(donationTypeFilter); + const donationTypeFilter = normalizeDonationTypeFilter(urlParams.get('tipjartype') || urlParams.get('tipjarunit') || urlParams.get('donationtype') || ''); + const sourceTypeFilter = normalizeFilterList(urlParams.get('tipjarsource') || urlParams.get('donationsource') || ''); + const nativeUnitMode = !!donationTypeFilter && donationTypeFilter !== 'usd'; + const nativeUnitLabel = urlParams.get('tipjarunitlabel') || getDonationTypeLabel(donationTypeFilter); // Fluid goal bar styling + recurring goal levels const fillStartColor = urlParams.get('fillstart') || urlParams.get('barcolorstart') || '#2196F3'; @@ -1259,12 +1259,17 @@

🏆 Top Dono document.addEventListener(eventName, primeDonationSound); }); - function normalizeFilterValue(value) { - return String(value || '').trim().toLowerCase(); - } - - function normalizeTipJarSourceValue(value) { - const source = normalizeFilterValue(value).replace(/[\s_-]+/g, ''); + function normalizeFilterValue(value) { + return String(value || '').trim().toLowerCase(); + } + + function normalizeDonationTypeFilter(value) { + const filter = normalizeFilterValue(value); + return filter === 'cash' ? 'usd' : filter; + } + + function normalizeTipJarSourceValue(value) { + const source = normalizeFilterValue(value).replace(/[\s_-]+/g, ''); if (source === 'youtubeshort' || source === 'youtubeshorts') { return 'youtube'; } @@ -1378,10 +1383,10 @@

🏆 Top Dono return { type: '', amount, label: nativeUnitLabel || 'units' }; } - function donationMatchesTypeFilter(unitInfo, rawDonation) { - if (!donationTypeFilter) return true; - - const filter = donationTypeFilter === 'cash' ? 'usd' : donationTypeFilter; + function donationMatchesTypeFilter(unitInfo, rawDonation) { + if (!donationTypeFilter) return true; + + const filter = normalizeDonationTypeFilter(donationTypeFilter); if (unitInfo && unitInfo.type) { const unitType = unitInfo.type === 'cash' ? 'usd' : unitInfo.type; if (filter === unitType) return true; From 453aca51ac2edb57f3390abc11851d2cc29663c7 Mon Sep 17 00:00:00 2001 From: steveseguin Date: Mon, 22 Jun 2026 23:07:53 -0400 Subject: [PATCH 08/30] Fix tipjar goal controls --- background.js | 16 +++++ popup.html | 15 +++++ popup.js | 21 ++++++ tipjar.html | 180 +++++++++++++++++++++++++++++++++++++++++--------- tts.js | 57 +++++++++++----- 5 files changed, 242 insertions(+), 47 deletions(-) diff --git a/background.js b/background.js index fe488f281..39276dd43 100644 --- a/background.js +++ b/background.js @@ -5912,6 +5912,14 @@ chrome.runtime.onMessage.addListener(async function (request, sender, sendRespon } else if (request.cmd && request.cmd === "resettipjar") { sendTargetP2P({ cmd: "resettipjar" }, "tipjar"); sendResponse({ state: isExtensionOn }); + } else if (request.cmd && request.cmd === "settipjaramount") { + sendTargetP2P({ + cmd: "settipjaramount", + value: request.value, + tipjarsource: request.tipjarsource || "", + tipjartype: request.tipjartype || "" + }, "tipjar"); + sendResponse({ state: isExtensionOn }); } else if (request.cmd && request.cmd === "stopentries") { toggleEntries(false); sendResponse({ state: isExtensionOn }); @@ -9038,6 +9046,14 @@ function setupSocket() { } else if (data.action && data.action === "resettipjar") { sendTargetP2P({ cmd: "resettipjar" }, "tipjar"); resp = true; + } else if (data.action && data.action === "settipjaramount") { + sendTargetP2P({ + cmd: "settipjaramount", + value: data.value, + tipjarsource: data.tipjarsource || "", + tipjartype: data.tipjartype || "" + }, "tipjar"); + resp = true; } else if (data.action && data.action === "resetpoll") { sendTargetP2P({ cmd: "resetpoll" }, "poll"); resp = true; diff --git a/popup.html b/popup.html index f8f38c5b0..f7b7886d8 100644 --- a/popup.html +++ b/popup.html @@ -10694,6 +10694,13 @@

🔧 General Options

Reset saved amount

+
+ + + +
@@ -10809,6 +10816,10 @@

🎯 Goal Settings

+
+ + +
+
+ + +
@@ -7739,7 +7779,7 @@

Blocked / Allowed Users:

- 🔮 Blocked users + 🔮 Blocked users
@@ -12191,10 +12231,20 @@

Other customization optio 🔁 Loop credits continuously

+
+ + Save credits list in this overlay +
+
+ +

+
+

Important: Enable "No Reflections" when relaying chat to prevent infinite echo loops. For detailed documentation, see the Event Flow Guide. For Kick reward sounds or media, use the Kick Channel Points / Rewards guide.

+
+

MIDI & Hotkey Control

@@ -1000,10 +1000,10 @@

Getting Started:

Flow Actions Overlay:

Add the Flow Actions URL as a browser source in OBS for audio/overlay actions to work. Find the URL in the app's "Flow Actions" section.

-
-

For detailed documentation, see the Event Flow Guide.

-
-
+
+

For detailed documentation, see the Event Flow Guide. For Kick reward sounds or media, use the Kick Channel Points / Rewards guide.

+
+

MIDI & Hotkey Control

diff --git a/docs/images/kick-channel-points-event-flow/event-flow-media-action-values.png b/docs/images/kick-channel-points-event-flow/event-flow-media-action-values.png new file mode 100644 index 0000000000000000000000000000000000000000..f28b2b250098ecd592024a025589da4057a7360e GIT binary patch literal 38522 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 E4^HL4LI3~& literal 0 HcmV?d00001 diff --git a/docs/images/kick-channel-points-event-flow/event-flow-reward-trigger.png b/docs/images/kick-channel-points-event-flow/event-flow-reward-trigger.png new file mode 100644 index 0000000000000000000000000000000000000000..3054c4dee956ce0937b032337f3ec46a87cd1121 GIT binary patch literal 92509 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 literal 0 HcmV?d00001 diff --git a/docs/images/kick-channel-points-event-flow/event-flow-test-panel.png b/docs/images/kick-channel-points-event-flow/event-flow-test-panel.png new file mode 100644 index 0000000000000000000000000000000000000000..22561fca2bfcf3d798dce85ac39c457e57288547 GIT binary patch literal 28012 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 D9z)?f literal 0 HcmV?d00001 diff --git a/docs/images/kick-channel-points-event-flow/flow-actions-popup-card.png b/docs/images/kick-channel-points-event-flow/flow-actions-popup-card.png new file mode 100644 index 0000000000000000000000000000000000000000..7d1eefd1b941e00c9229b50a6f501e1ddd39eeb3 GIT binary patch literal 15122 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 Brd9v| literal 0 HcmV?d00001 diff --git a/docs/images/kick-channel-points-event-flow/kick-bridge-source.png b/docs/images/kick-channel-points-event-flow/kick-bridge-source.png new file mode 100644 index 0000000000000000000000000000000000000000..e725fd08e9c734e5c503f1a8701fca985dea1870 GIT binary patch literal 26029 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 Date: Tue, 23 Jun 2026 19:38:21 -0400 Subject: [PATCH 15/30] docs(kick): improve wording and update heading in channel points guide Reword the short answer for clarity and change the section heading from "What Steve should tell the user" to "Overview". [auto-enhanced] --- docs/kick-channel-points-event-flow.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/kick-channel-points-event-flow.md b/docs/kick-channel-points-event-flow.md index 2696d9d1a..0a446dd7e 100644 --- a/docs/kick-channel-points-event-flow.md +++ b/docs/kick-channel-points-event-flow.md @@ -1,8 +1,8 @@ # Kick Channel Points / Rewards to Event Flow Actions -Short answer: do this in the Event Flow Editor, and keep the Flow Actions overlay open for the sound or media output. +Use the Event Flow Editor to listen for Kick reward redemptions, and keep the Flow Actions overlay open for sound or media output. -## What Steve should tell the user +## Overview Kick calls these channel rewards/redemptions. In Social Stream Ninja they come through as a reward event, so the Event Flow trigger to use is Channel Point Redemption. From 61079d6ef037fd03ab747a2c7cb53fb6d38cf417 Mon Sep 17 00:00:00 2001 From: steveseguin Date: Tue, 23 Jun 2026 19:40:40 -0400 Subject: [PATCH 16/30] Sync beta From f1d3e2ba6a35f9787d9ff3c07a0cd673b46b5521 Mon Sep 17 00:00:00 2001 From: steveseguin Date: Tue, 23 Jun 2026 20:53:14 -0400 Subject: [PATCH 17/30] docs(agents): add AI agent documentation framework with inventory and extraction plan Introduce the initial documentation structure under `docs/agents/` to support AI agents answering questions about Social Stream Ninja. - **00-inventory-and-plan.md**: catalogs existing project sources and proposes a comprehensive 12-section documentation plan - **01-extraction-checklist.md**: defines extraction levels (quick, heavy, intense), a master checklist for all components, and an extraction pass log [auto-enhanced] --- docs/agents/00-inventory-and-plan.md | 302 ++++++++ docs/agents/01-extraction-checklist.md | 197 ++++++ docs/agents/01-product-map.md | 35 + docs/agents/02-installation-and-surfaces.md | 35 + docs/agents/02-resource-manifest.md | 651 ++++++++++++++++++ docs/agents/03-extension-architecture.md | 108 +++ docs/agents/04-standalone-app-architecture.md | 111 +++ .../05-message-flow-and-event-contracts.md | 129 ++++ .../06-settings-sessions-and-storage.md | 110 +++ .../07-overlays-and-pages/custom-overlays.md | 29 + docs/agents/07-overlays-and-pages/dock.md | 29 + docs/agents/07-overlays-and-pages/featured.md | 28 + docs/agents/07-overlays-and-pages/index.md | 24 + .../07-overlays-and-pages/multi-alerts.md | 26 + .../waitlist-polls-games.md | 30 + docs/agents/08-platform-sources/discord.md | 25 + docs/agents/08-platform-sources/facebook.md | 27 + .../generic-and-custom-sources.md | 30 + docs/agents/08-platform-sources/index.md | 28 + docs/agents/08-platform-sources/instagram.md | 25 + docs/agents/08-platform-sources/kick.md | 32 + docs/agents/08-platform-sources/rumble.md | 26 + docs/agents/08-platform-sources/tiktok.md | 32 + docs/agents/08-platform-sources/twitch.md | 29 + docs/agents/08-platform-sources/youtube.md | 33 + .../09-api-and-integrations/ai-features.md | 34 + .../event-flow-editor.md | 32 + docs/agents/09-api-and-integrations/index.md | 17 + docs/agents/09-api-and-integrations/obs.md | 30 + .../streamdeck-companion.md | 26 + .../09-api-and-integrations/streamerbot.md | 26 + docs/agents/09-api-and-integrations/tts.md | 32 + .../websocket-http-api.md | 30 + .../10-troubleshooting/auth-and-sign-in.md | 27 + .../10-troubleshooting/desktop-app-issues.md | 29 + .../extension-not-capturing.md | 29 + docs/agents/10-troubleshooting/index.md | 17 + .../10-troubleshooting/obs-overlay-display.md | 28 + .../platform-known-issues.md | 29 + .../agents/10-troubleshooting/quick-triage.md | 126 ++++ .../settings-loss-and-backups.md | 30 + docs/agents/11-support-kb/common-questions.md | 31 + .../agents/11-support-kb/historical-issues.md | 25 + docs/agents/11-support-kb/mining-method.md | 27 + .../11-support-kb/support-source-map.md | 28 + .../unresolved-or-stale-claims.md | 26 + docs/agents/12-development/adding-a-source.md | 30 + .../build-and-release-boundaries.md | 28 + docs/agents/12-development/repo-map.md | 29 + .../12-development/shared-code-rules.md | 28 + .../12-development/testing-and-validation.md | 28 + docs/agents/99-agent-index.md | 40 ++ docs/agents/AGENT.md | 78 +++ docs/agents/_templates/extraction-pass.md | 27 + docs/agents/_templates/topic-page.md | 38 + 55 files changed, 3136 insertions(+) create mode 100644 docs/agents/00-inventory-and-plan.md create mode 100644 docs/agents/01-extraction-checklist.md create mode 100644 docs/agents/01-product-map.md create mode 100644 docs/agents/02-installation-and-surfaces.md create mode 100644 docs/agents/02-resource-manifest.md create mode 100644 docs/agents/03-extension-architecture.md create mode 100644 docs/agents/04-standalone-app-architecture.md create mode 100644 docs/agents/05-message-flow-and-event-contracts.md create mode 100644 docs/agents/06-settings-sessions-and-storage.md create mode 100644 docs/agents/07-overlays-and-pages/custom-overlays.md create mode 100644 docs/agents/07-overlays-and-pages/dock.md create mode 100644 docs/agents/07-overlays-and-pages/featured.md create mode 100644 docs/agents/07-overlays-and-pages/index.md create mode 100644 docs/agents/07-overlays-and-pages/multi-alerts.md create mode 100644 docs/agents/07-overlays-and-pages/waitlist-polls-games.md create mode 100644 docs/agents/08-platform-sources/discord.md create mode 100644 docs/agents/08-platform-sources/facebook.md create mode 100644 docs/agents/08-platform-sources/generic-and-custom-sources.md create mode 100644 docs/agents/08-platform-sources/index.md create mode 100644 docs/agents/08-platform-sources/instagram.md create mode 100644 docs/agents/08-platform-sources/kick.md create mode 100644 docs/agents/08-platform-sources/rumble.md create mode 100644 docs/agents/08-platform-sources/tiktok.md create mode 100644 docs/agents/08-platform-sources/twitch.md create mode 100644 docs/agents/08-platform-sources/youtube.md create mode 100644 docs/agents/09-api-and-integrations/ai-features.md create mode 100644 docs/agents/09-api-and-integrations/event-flow-editor.md create mode 100644 docs/agents/09-api-and-integrations/index.md create mode 100644 docs/agents/09-api-and-integrations/obs.md create mode 100644 docs/agents/09-api-and-integrations/streamdeck-companion.md create mode 100644 docs/agents/09-api-and-integrations/streamerbot.md create mode 100644 docs/agents/09-api-and-integrations/tts.md create mode 100644 docs/agents/09-api-and-integrations/websocket-http-api.md create mode 100644 docs/agents/10-troubleshooting/auth-and-sign-in.md create mode 100644 docs/agents/10-troubleshooting/desktop-app-issues.md create mode 100644 docs/agents/10-troubleshooting/extension-not-capturing.md create mode 100644 docs/agents/10-troubleshooting/index.md create mode 100644 docs/agents/10-troubleshooting/obs-overlay-display.md create mode 100644 docs/agents/10-troubleshooting/platform-known-issues.md create mode 100644 docs/agents/10-troubleshooting/quick-triage.md create mode 100644 docs/agents/10-troubleshooting/settings-loss-and-backups.md create mode 100644 docs/agents/11-support-kb/common-questions.md create mode 100644 docs/agents/11-support-kb/historical-issues.md create mode 100644 docs/agents/11-support-kb/mining-method.md create mode 100644 docs/agents/11-support-kb/support-source-map.md create mode 100644 docs/agents/11-support-kb/unresolved-or-stale-claims.md create mode 100644 docs/agents/12-development/adding-a-source.md create mode 100644 docs/agents/12-development/build-and-release-boundaries.md create mode 100644 docs/agents/12-development/repo-map.md create mode 100644 docs/agents/12-development/shared-code-rules.md create mode 100644 docs/agents/12-development/testing-and-validation.md create mode 100644 docs/agents/99-agent-index.md create mode 100644 docs/agents/AGENT.md create mode 100644 docs/agents/_templates/extraction-pass.md create mode 100644 docs/agents/_templates/topic-page.md diff --git a/docs/agents/00-inventory-and-plan.md b/docs/agents/00-inventory-and-plan.md new file mode 100644 index 000000000..32e7972c5 --- /dev/null +++ b/docs/agents/00-inventory-and-plan.md @@ -0,0 +1,302 @@ +# SSN AI Documentation Inventory And Plan + +Checked on 2026-06-23. + +## Goal + +Build an exhaustive markdown documentation set for AI agents that need to answer questions about Social Stream Ninja, including both the Chrome extension in `social_stream` and the standalone Electron app in `ssapp`. + +This first pass creates the working folder, records what already exists, and lays out the proposed documentation structure. It does not create the full documentation set yet. + +## Write Location + +All new AI documentation should live under: + +`C:\Users\steve\Code\social_stream\docs\agents` + +No other files should be edited for this documentation project unless Steve explicitly changes the scope. + +## Existing Source Map + +### `C:\Users\steve\Code\social_stream` + +Primary source for the Chrome extension, public web overlays, shared source scripts, and code loaded by the standalone app. + +Observed structure: + +- `manifest.json`: Chrome extension Manifest V3 config. Version observed: `3.50.1`. +- `service_worker.js`: extension service worker and routing shim into the background page. +- `background.html` / `background.js`: long-running extension background page logic. +- `popup.html` / `popup.js`: main extension settings UI. +- `dock.html`: dashboard/control surface for incoming messages, pinning, queues, TTS, OBS control, and related workflows. +- `featured.html`: featured-message overlay. +- `sources/`: platform source scripts. This is the largest folder observed, with classic content scripts, platform icons, and `sources/websocket/*` connector pages/scripts. +- `providers/`: newer environment-agnostic provider cores, currently including Kick, Twitch, and YouTube. +- `shared/`: shared utilities and vendors used across extension, app, and some standalone pages. +- `actions/`: Event Flow Editor and action-flow system. +- `settings/`: extension options pages and config JSON. +- `themes/`, `media/`, `icons/`, `audio/`, `games/`, `lite/`: user-facing pages/assets and standalone surfaces. +- `scripts/`: test, validation, sync, and Playwright helper scripts. +- `tests/`: regression and RAG tests. +- `docs/`: existing public docs site content. + +Approximate top-level source counts from `rg --files`: + +- `sources`: 381 files +- `thirdparty`: 114 files +- `icons`: 86 files +- `themes`: 68 files +- `docs`: 51 files +- `scripts`: 39 files +- `tests`: 35 files +- `actions`: 28 files +- `lite`: 18 files +- `games`: 17 files +- `translations`: 16 files +- `shared`: 12 files +- `providers`: 5 files + +Existing docs worth mining first: + +- `README.md`: product overview, supported sites, extension install, standalone version, customization, TTS, API, known issues, Zoom, OBS remote scenes. +- `about.md`: compact AI integration overview. +- `api.md`: WebSocket API, HTTP API, command routing, featured/dock/waitlist/battle controls, StreamDeck, Bitfocus Companion. +- `parameters.md`: URL parameters for dock, overlays, TTS, donation/member handling, OBS integration, automation, debugging. +- `docs/event-reference.html`: canonical event payload vocabulary and message fields. +- `docs/customoverlays.md`: custom overlay connection methods and payload handling. +- `docs/ssapp.html`: standalone app public documentation. +- `docs/tiktok-guide.html`: TikTok setup and troubleshooting. +- `docs/local-tts.html` and `docs/tts.html`: TTS setup and providers. +- `docs/services.html`, `docs/settings.html`, `docs/supported-sites.html`, `docs/guides.html`, `docs/support.html`: user-facing setup and support material. +- `docs/kick-channel-points-event-flow.md`: recent Event Flow guide for Kick rewards. +- `actions/event-flow-guide.html` and `actions/STATE_NODES_EXPLANATION.md`: action-flow behavior. + +Important repo instruction already present: + +- `sources/` and `sources/websocket/` scripts are shared by the Chrome extension and Electron app. +- Browser-facing code should stay Chrome 80 friendly unless Steve says otherwise. +- Provider cores should remain environment agnostic. +- Remote executable scripts/WASM should not be introduced into extension code. +- `docs/event-reference.html` is the canonical event payload reference. + +### `C:\Users\steve\Code\ssapp` + +Standalone Electron app source. This app uses Social Stream source files from `C:\Users\steve\Code\social_stream` as the primary runtime source. The fallback bundle is disposable and was intentionally not inspected. + +Observed structure: + +- `main.js`: main Electron process. Very large; handles windows, source loading, IPC, app lifecycle, OAuth handlers, local services, and platform-specific glue. +- `preload.js`: exposes `window.ninjafy` and Electron IPC bridges to extension-style pages/scripts. +- `state.js`: app state manager, source modes, session bindings, localStorage migration/compatibility, and TikTok/YouTube global state. +- `index.html`, `main.css`, `renderer.js`: app UI shell. +- `tiktok/connection-manager.js`: TikTok connection management and WebSocket/legacy handling. +- `tiktok-signing/electron-signer.js`: TikTok signing helper. +- `resources/electron-*-handler.js`: OAuth and integration handlers for YouTube, Twitch, Facebook, Kick, Velora, VPZone, Spotify, and others. +- `resources/kick-ws-client.js`: Kick WebSocket bridge client. +- `tests/electron/*`: diagnostics and regression tests for settings, stability, IPC, path security, source URL parsing, and TTS. +- `tests/tiktok/*`: TikTok integration/regression harnesses. +- `scripts/*`: build, fallback update, dependency patching, VirusTotal submit, and related automation. + +Observed app package info: + +- Package name: `SocialStream` +- Version observed: `0.3.129` +- Main entry: `main.js` +- Key commands: `npm run start`, `npm run start2`, `npm run start3`, `npm run update:fallback`, `npm run build:*`, and targeted regression scripts. + +Existing docs worth mining: + +- `README.md`: standalone features, download, build, usage, YouTube OAuth troubleshooting, configuration. +- `RELEASE.md`: release boundaries and critical rule that app releases belong in `steveseguin/social_stream`, not `ssapp`. +- `CONTRIBUTING.md`: development setup and contribution notes. +- `CODE_SIGNING.md`: signing verification notes. +- `tests/*`: expected behavior and known regressions. + +Do not mine for normal docs: + +- `resources/social_stream_fallback`: disposable fallback bundle, not source of truth. + +### `C:\Users\steve\Code\stevesbot` + +Historical support and knowledge base material. This is a supporting evidence source, not the product source of truth. + +Observed structure: + +- `resources/instructions/social-stream-support.md`: concise current support guidance for SSN, SSN Desktop App, Electron Capture, and Caption.Ninja. +- `resources/learnings/social-stream-ninja-top-issues.md`: generated summary of common SSN support issues. +- `resources/learnings/support-qa/social-stream-qa.md`: larger social-stream support Q&A. +- `resources/learnings/support-qa/social-stream-qa-expanded.md`: expanded support Q&A. +- `resources/learnings/support-qa/social-stream-configuration.md`: configuration-focused support notes. +- `resources/learnings/product-notes/social-stream-architecture.md`: architecture-oriented notes. +- `resources/learnings/playbooks/playbook-obs-overlay-issues.md`: OBS overlay troubleshooting. +- `resources/learnings/playbooks/playbook-tiktok-connection.md`: TikTok connection troubleshooting. +- `resources/learnings/playbooks/triage-macros.md` and related rapid-response files: support triage material. +- `data/mined-threads/*.jsonl`: mined support-thread summaries. +- `data/sqlite/knowledge.sqlite` and `resources/knowledge.sqlite`: summarized mined-thread database. +- `data/sqlite/stevesbot.sqlite`: curated records, Q&A entries, transcripts, workflow data. +- `data/sqlite/archive.sqlite`: raw archived Discord messages. + +Observed database tables and counts: + +- `knowledge.sqlite` + - Main table: `mined_threads` + - Count observed: 2,264 rows + - Useful columns: thread name, channel, source URL, timestamps, message count, participants JSON, summary, problem statement, solution, resolved flag, keywords/products/platforms/error signals JSON, category, searchable text. +- `stevesbot.sqlite` + - Useful tables: `support_records`, `qa_entries`, `transcripts` + - Counts observed: `support_records` 499, `qa_entries` 358, `transcripts` 13,272 +- `archive.sqlite` + - Useful table: `archived_messages` + - Count observed: 47,600 messages + +Exclusions: + +- `resources/secrets`: never read or document from this folder. +- VDO.Ninja, Raspberry Ninja, and unrelated product material should be ignored unless it directly affects SSN setup or integration. +- Raw Discord archive data should be treated as private support evidence and summarized/anonymized. + +## Proposed Documentation Structure + +The documentation set should be split by job-to-be-done, not only by code folder. That makes it easier for AI agents to answer support, setup, and development questions. + +```text +docs/agents/ + AGENT.md + 00-inventory-and-plan.md + 01-product-map.md + 02-installation-and-surfaces.md + 03-extension-architecture.md + 04-standalone-app-architecture.md + 05-message-flow-and-event-contracts.md + 06-settings-sessions-and-storage.md + 07-overlays-and-pages/ + dock.md + featured.md + multi-alerts.md + waitlist-polls-games.md + custom-overlays.md + 08-platform-sources/ + index.md + youtube.md + tiktok.md + twitch.md + kick.md + facebook.md + instagram.md + rumble.md + discord.md + generic-and-custom-sources.md + 09-api-and-integrations/ + websocket-http-api.md + obs.md + streamdeck-companion.md + streamerbot.md + event-flow-editor.md + tts.md + ai-features.md + 10-troubleshooting/ + quick-triage.md + extension-not-capturing.md + desktop-app-issues.md + auth-and-sign-in.md + obs-overlay-display.md + settings-loss-and-backups.md + platform-known-issues.md + 11-support-kb/ + mining-method.md + support-source-map.md + common-questions.md + historical-issues.md + unresolved-or-stale-claims.md + 12-development/ + repo-map.md + adding-a-source.md + shared-code-rules.md + testing-and-validation.md + build-and-release-boundaries.md + 99-agent-index.md +``` + +## Proposed Page Roles + +### `01-product-map.md` + +Explain what SSN is, what the extension does, what the standalone app does, which pages are overlays/tools, and how users typically combine SSN with OBS. + +### `02-installation-and-surfaces.md` + +Cover Chrome extension install/update, extension stores, standalone app install, beta/stable distinction, hosted pages, local files, and when to use each surface. + +### `03-extension-architecture.md` + +Document extension runtime flow: Manifest V3 service worker, background page, popup settings UI, content scripts, storage, messaging, source windows, and permissions. + +### `04-standalone-app-architecture.md` + +Document Electron windows, `window.ninjafy`, IPC bridges, source-file resolution, OAuth handlers, TikTok/Kick/YouTube special handling, state persistence, and app-specific differences. + +### `05-message-flow-and-event-contracts.md` + +Make one agent-friendly source of truth for message payloads, event types, `meta`, source-to-background-to-dock/overlay flow, VDO.Ninja bridge flow, WebSocket API flow, and compatibility expectations. + +### `06-settings-sessions-and-storage.md` + +Document session IDs, passwords, Chrome sync/local storage, app localStorage/electron-store behavior, export/import, settings loss, source bindings, and URL parameter interactions. + +### `07-overlays-and-pages/*` + +Break out dock, featured overlay, alert pages, queue/waitlist/poll/game pages, custom overlays, styling, CSS variables, and OBS browser source behavior. + +### `08-platform-sources/*` + +Create one page per high-value platform with setup steps, source file locations, modes, auth requirements, known failure modes, and support-derived guidance. Start with YouTube, TikTok, Twitch, Kick, Facebook, Instagram, Rumble, Discord, and generic/custom sources. + +### `09-api-and-integrations/*` + +Cover external control and integration: WebSocket/HTTP API, channels, OBS remote scene control, StreamDeck, Bitfocus Companion, Streamer.bot, Event Flow Editor, TTS providers, and AI/cohost features. + +### `10-troubleshooting/*` + +Convert support knowledge into practical triage pages. Each page should include symptoms, likely causes, exact checks, known platform quirks, and when to escalate as a platform-side breakage. + +### `11-support-kb/*` + +Document how the support data was mined, which sources are trusted, how claims are validated against code, which support answers are historical, and which questions still need source verification. + +### `12-development/*` + +Document how to safely change SSN: repo map, adding new platform sources, shared-code compatibility rules, tests that matter, Electron differences, build commands, release boundaries, and event-reference update rules. + +### `99-agent-index.md` + +Final navigation index for AI agents. This should be generated last, after the detailed pages exist. + +## Suggested Build Order + +1. Product map and install/surface docs. +2. Message flow and event contract docs, because many other pages depend on these. +3. Extension architecture and standalone app architecture. +4. Settings/session/storage docs. +5. Overlay/page docs. +6. Platform source docs, starting with the highest support volume: TikTok, YouTube, Kick, Twitch, Rumble. +7. API/integration docs. +8. Troubleshooting docs from support data. +9. Development docs. +10. Final agent index. + +## Verification Method + +For each page: + +- Link claims back to specific source files or existing docs. +- Prefer current code over historical support answers. +- Mark support-derived claims as historical until source-confirmed. +- Keep extension/app differences explicit. +- Add an "Open Questions" section when a behavior is inferred but not confirmed. + +## First-Pass Open Questions + +- Which support categories in `stevesbot` should be considered in scope beyond SSN Desktop App, Electron Capture, Caption.Ninja, and OBS overlays? +- Should this documentation include exact UI labels from `popup.html`, or summarize behavior and reference source locations? +- Should raw support examples be anonymized into scenario pages, or only used to rank common problems? +- Should generated agent docs eventually be moved into public docs, or remain temporary/private under `docs/agents`? diff --git a/docs/agents/01-extraction-checklist.md b/docs/agents/01-extraction-checklist.md new file mode 100644 index 000000000..d77fabf75 --- /dev/null +++ b/docs/agents/01-extraction-checklist.md @@ -0,0 +1,197 @@ +# SSN Documentation Extraction Checklist + +Last updated on 2026-06-24. + +## Purpose + +Use this file to track which source files and support datasets have been processed for the SSN AI documentation set. The goal is to support multiple AI passes without redoing the same work or skipping important resource areas. + +Only write extraction notes and status changes inside `C:\Users\steve\Code\social_stream\docs\agents`. + +## Extraction Levels + +### Quick + +Use quick extraction when the goal is coverage and orientation. + +Record: + +- What the file/dataset is for +- Major concepts, pages, features, or workflows +- Obvious links to planned docs +- Any high-risk unknowns needing deeper review + +Expected output: short notes, source map entries, and candidate doc sections. + +### Heavy + +Use heavy extraction when a source is important to product behavior or user support. + +Record: + +- Function/page/component responsibilities +- Message flows, settings, storage, APIs, URL params, and runtime boundaries +- User setup steps +- Common failure modes +- Chrome extension vs standalone app differences +- Source-backed claims with file references + +Expected output: usable topic documentation. + +### Intense + +Use intense extraction for source-of-truth behavior, fragile integrations, or high-volume support issues. + +Record: + +- Line-level behavior and key state transitions +- Edge cases, retries, fallbacks, cleanup, persistence, and security boundaries +- Cross-checks against current code, existing docs, tests, and support history +- Known stale/historical claims +- Repro or validation notes when practical + +Expected output: final-grade documentation and troubleshooting pages. + +## Status Values + +Use these labels in pass notes: + +- `not-started` +- `quick-complete` +- `heavy-complete` +- `intense-complete` +- `needs-refresh` +- `blocked` +- `skip` + +## Pass Log + +Add one entry per extraction pass. + +| Date | Agent | Scope | Level | Output files | Status | Notes | +| --- | --- | --- | --- | --- | --- | --- | +| 2026-06-23 | Codex | Initial repo/support inventory | Quick | `00-inventory-and-plan.md`, `01-extraction-checklist.md`, `02-resource-manifest.md` | quick-complete | Created tracker and manifest. No detailed extraction yet. | +| 2026-06-23 | Codex | Documentation framework and starter pages | Quick | Topic files under `01-*` through `12-*`, `_templates/`, `99-agent-index.md` | quick-complete | Created starter files and section scaffolds. Detailed extraction still not started. | +| 2026-06-24 | Codex | Backbone architecture, flow, storage, and triage notes | Heavy | `03-extension-architecture.md`, `04-standalone-app-architecture.md`, `05-message-flow-and-event-contracts.md`, `06-settings-sessions-and-storage.md`, `10-troubleshooting/quick-triage.md`, `AGENT.md`, `99-agent-index.md` | heavy-complete | First source-backed pass using manifest, service worker, background, app preload/state/main notes, and support history. Needs field-level/intense passes later. | + +## Master Checklist + +### Product And Existing Docs + +- [ ] Quick: `social_stream/README.md`, `about.md`, `ai.md` +- [ ] Heavy: product surfaces, install modes, extension/app differences +- [ ] Intense: verify all claims against current code and public docs + +- [ ] Quick: `social_stream/api.md`, `parameters.md`, `docs/event-reference.html` +- [ ] Heavy: API commands, URL params, event schema, message payload contract +- [ ] Intense: field-by-field payload and command behavior with source references + +- [ ] Quick: `social_stream/docs/*.html`, `social_stream/docs/*.md` +- [ ] Heavy: public docs coverage map and stale-claim review +- [ ] Intense: only for docs that are canonical source references + +### Extension Runtime + +- [ ] Quick: `manifest.json`, `service_worker.js`, `background.html`, `background.js` +- [ ] Heavy: extension lifecycle, background routing, storage, source capture, messaging +- [ ] Intense: source-to-dock message flow and external API behavior + +- [ ] Quick: `popup.html`, `popup.js`, `settings/*`, `shared/config/*` +- [ ] Heavy: settings UI, storage keys, session/password behavior, generated parameter docs +- [ ] Intense: settings migration, sync/local behavior, app parity + +### Shared Pages And Overlays + +- [ ] Quick: `dock.html`, `featured.html`, `multi-alerts.*`, `tts.*` +- [ ] Heavy: dock controls, featured overlay, alert routing, TTS behavior +- [ ] Intense: OBS/browser-source troubleshooting and payload/rendering edge cases + +- [ ] Quick: overlay/tool pages listed in `02-resource-manifest.md` +- [ ] Heavy: high-use pages only: waitlist, poll, timer, tipjar, giveaway, actions, chatbot/cohost +- [ ] Intense: only pages tied to frequent support issues or APIs + +### Platform Sources + +- [ ] Quick: all active `social_stream/sources/*.js` +- [ ] Heavy: YouTube, TikTok, Twitch, Kick, Facebook, Instagram, Rumble, Discord, generic/custom sources +- [ ] Intense: TikTok, YouTube, Kick, Twitch, and any platform with recurring support failures + +- [ ] Quick: `social_stream/sources/websocket/*` +- [ ] Heavy: WebSocket setup, auth, message sending, fallback behavior +- [ ] Intense: YouTube, TikTok-adjacent app behavior, Kick, Twitch EventSub, Rumble + +- [ ] Quick: `social_stream/providers/*`, `shared/*` +- [ ] Heavy: provider core responsibilities and extension/app compatibility rules +- [ ] Intense: provider cores used by fragile/high-value integrations + +### Event Flow And Integrations + +- [ ] Quick: `actions/*` +- [ ] Heavy: Event Flow Editor, triggers, actions, state nodes, tests +- [ ] Intense: custom JS actions, media actions, Kick rewards, OBS actions + +- [ ] Quick: `api.md`, `streamerbot.html`, `obs-websocket-test.html`, StreamDeck/Companion sections +- [ ] Heavy: integration setup, command paths, troubleshooting +- [ ] Intense: API command contract and OBS remote-control behavior + +### Standalone App + +- [ ] Quick: `ssapp/README.md`, `RELEASE.md`, `package.json` +- [ ] Heavy: app surfaces, build/run commands, release boundaries +- [ ] Intense: release docs only if doing release-related docs + +- [ ] Quick: `ssapp/main.js`, `preload.js`, `state.js`, `index.html`, `renderer.js` +- [ ] Heavy: Electron app architecture, source loading, IPC, state persistence +- [ ] Intense: settings loss, source resolution, security/path validation, message bridge + +- [ ] Quick: `ssapp/resources/electron-*-handler.js`, `kick-ws-client.js` +- [ ] Heavy: OAuth and platform handlers +- [ ] Intense: YouTube/Twitch/Facebook/Kick/Velora/VPZone auth flows + +- [ ] Quick: `ssapp/tiktok/*`, `ssapp/tiktok-signing/*`, `ssapp/tests/tiktok/*` +- [ ] Heavy: TikTok modes, signing, fallbacks, regression expectations +- [ ] Intense: TikTok support/troubleshooting and current behavior docs + +### Support Knowledge Base + +- [ ] Quick: `stevesbot/resources/instructions/social-stream-support.md` +- [ ] Heavy: support answer style, top recurring advice, escalation rules +- [ ] Intense: verify every user-facing troubleshooting claim against code/docs + +- [ ] Quick: `stevesbot/resources/learnings/social-stream-ninja-top-issues.md` +- [ ] Heavy: common issues and platform-specific support history +- [ ] Intense: stale/historical claim review + +- [ ] Quick: SSN files in `stevesbot/resources/learnings/support-qa/*` +- [ ] Heavy: common Q&A extraction into troubleshooting pages +- [ ] Intense: scenario-by-scenario validation against current source + +- [ ] Quick: `stevesbot/data/sqlite/knowledge.sqlite` and `resources/knowledge.sqlite` +- [ ] Heavy: category/platform/product queries for SSN support issues +- [ ] Intense: high-frequency platform support threads and contradiction checks + +- [ ] Quick: `stevesbot/data/sqlite/stevesbot.sqlite` +- [ ] Heavy: curated support records and Q&A entries +- [ ] Intense: only for high-risk/high-volume claims + +- [ ] Quick: `stevesbot/data/sqlite/archive.sqlite` +- [ ] Heavy: raw message search only to confirm real-world symptom wording or frequency +- [ ] Intense: anonymized deep dives only for unresolved or unclear support issues + +### Tests And Validation Material + +- [ ] Quick: `social_stream/tests/*`, `social_stream/scripts/playwright-*.cjs` +- [ ] Heavy: expected behavior and testable workflows +- [ ] Intense: only for features with current E2E coverage or fragile regressions + +- [ ] Quick: `ssapp/tests/electron/*`, `ssapp/tests/tiktok/*` +- [ ] Heavy: app regression expectations and diagnostics +- [ ] Intense: settings loss, source URL parsing, TikTok connection behavior + +## Row Template For New Detailed Tracking + +Use this when a pass needs file-level status. + +| Source | Type | Target doc | Current level | Last checked | Notes | +| --- | --- | --- | --- | --- | --- | +| `relative/path.ext` | code/doc/support/db | `planned-doc.md` | not-started | | | diff --git a/docs/agents/01-product-map.md b/docs/agents/01-product-map.md new file mode 100644 index 000000000..b98090213 --- /dev/null +++ b/docs/agents/01-product-map.md @@ -0,0 +1,35 @@ +# SSN Product Map + +Status: framework only. Detailed extraction not started. + +## Purpose + +This page explains what Social Stream Ninja is, what surfaces it includes, and how those surfaces fit together for live chat capture, dashboards, overlays, automation, TTS, and AI tools. + +## Source Anchors + +- `C:\Users\steve\Code\social_stream\README.md` +- `C:\Users\steve\Code\social_stream\about.md` +- `C:\Users\steve\Code\social_stream\docs\features.html` +- `C:\Users\steve\Code\social_stream\docs\ssapp.html` +- `C:\Users\steve\Code\ssapp\README.md` +- `C:\Users\steve\Code\stevesbot\resources\instructions\social-stream-support.md` + +## Starter Notes + +SSN has at least two primary delivery surfaces: the Chrome extension and the standalone Electron app. The extension captures chat from many platform pages through browser scripts. The standalone app wraps the same Social Stream source files inside Electron and adds app-specific source management, OAuth helpers, persistence behavior, and platform glue. + +Public overlay/tool pages such as `dock.html`, `featured.html`, alert pages, games, TTS pages, and API examples are part of the same ecosystem. Some pages are shipped with the extension, some are hosted, and some are used by the app. + +## Planned Sections + +- What SSN does +- Chrome extension vs standalone app +- Hosted pages vs packaged pages +- OBS workflow overview +- Source windows, dashboard, featured overlay, and optional tools +- AI/cohost, TTS, Event Flow, and external integrations + +## Open Questions + +- Which related products should be included in this product map: Electron Capture, Caption.Ninja, VDO.Ninja bridge, or only SSN proper? diff --git a/docs/agents/02-installation-and-surfaces.md b/docs/agents/02-installation-and-surfaces.md new file mode 100644 index 000000000..ccd74d5e5 --- /dev/null +++ b/docs/agents/02-installation-and-surfaces.md @@ -0,0 +1,35 @@ +# Installation And Surfaces + +Status: framework only. Detailed extraction not started. + +## Purpose + +This page documents how users install, open, update, and choose between SSN surfaces: Chrome extension, standalone app, hosted pages, local pages, beta builds, and source/development mode. + +## Source Anchors + +- `social_stream/README.md` +- `social_stream/docs/download.html` +- `social_stream/docs/ssapp.html` +- `ssapp/README.md` +- `ssapp/package.json` +- `ssapp/RELEASE.md` + +## Starter Notes + +The Chrome extension and standalone app are not interchangeable in every workflow. The extension runs in Chrome and benefits from normal browser login sessions. The app runs in Electron and can manage sources without the extension, but some embedded sign-in flows can be blocked by platforms. + +## Planned Sections + +- Chrome extension install and update +- Browser store installs +- Manual unpacked extension install +- Standalone app install +- Stable vs beta +- Hosted overlay URLs +- Local/source mode for development +- When to recommend extension vs app + +## Open Questions + +- Which install/update paths should be treated as current primary guidance? diff --git a/docs/agents/02-resource-manifest.md b/docs/agents/02-resource-manifest.md new file mode 100644 index 000000000..d7a2ff0ac --- /dev/null +++ b/docs/agents/02-resource-manifest.md @@ -0,0 +1,651 @@ +# SSN Resource Manifest For AI Documentation + +Checked on 2026-06-23. + +This file lists the source material that should be considered for SSN AI documentation extraction. It is a manifest, not the finished docs. + +## Exclusions + +Do not use these for extraction unless Steve explicitly changes scope: + +- `C:\Users\steve\Code\ssapp\resources\social_stream_fallback` +- `C:\Users\steve\Code\stevesbot\resources\secrets` +- `node_modules`, `.git`, build output, temp folders, logs, and backup databases +- Non-SSN support material unless it directly affects SSN setup or integration + +## Extraction Priority + +- `P0`: source of truth or high-impact user support +- `P1`: important feature docs or current behavior support +- `P2`: useful context, tests, examples, or lower-volume features +- `P3`: assets, historical files, generated support material, or optional context + +## Social Stream Repo + +Root: `C:\Users\steve\Code\social_stream` + +Observed candidate resource counts: + +- `sources`: 381 files +- root files: 119 files +- `thirdparty`: 114 files +- `icons`: 86 files +- `themes`: 68 files +- `docs`: 51 files +- `scripts`: 39 files +- `tests`: 35 files +- `actions`: 28 files +- `lite`: 18 files +- `games`: 17 files +- `translations`: 16 files +- `shared`: 12 files +- `providers`: 5 files + +### P0 Core Runtime + +- `manifest.json` +- `service_worker.js` +- `background.html` +- `background.js` +- `popup.html` +- `popup.js` +- `dock.html` +- `featured.html` +- `api.md` +- `parameters.md` +- `docs/event-reference.html` +- `docs/customoverlays.md` +- `README.md` +- `about.md` + +### P0/P1 Shared Config And Provider Cores + +- `shared/config/settingsDefinitions.js` +- `shared/config/urlParameters.js` +- `shared/utils/html.js` +- `shared/utils/scriptLoader.js` +- `shared/utils/twitchEmotes.js` +- `shared/ai/browserModelCatalog.js` +- `shared/ai/kokoroAssetCatalog.js` +- `shared/ai/localBrowserLLM.js` +- `shared/aiPrompt/overlayStore.js` +- `providers/kick/core.js` +- `providers/twitch/chatClient.js` +- `providers/youtube/contextResolver.js` +- `providers/youtube/liveChat.js` +- `providers/youtube/proto/stream_list.proto` + +### P0/P1 Existing Docs + +- `docs/ai-cohost-guide.html` +- `docs/appImage.md` +- `docs/commands.html` +- `docs/custom-fonts.html` +- `docs/customoverlays.md` +- `docs/data/services.json` +- `docs/download.html` +- `docs/event-reference.html` +- `docs/features.html` +- `docs/first-time-chatters.html` +- `docs/guides.html` +- `docs/hype-train-top-bar.html` +- `docs/index.html` +- `docs/kick-channel-points-event-flow.md` +- `docs/local-tts.html` +- `docs/services.html` +- `docs/settings.html` +- `docs/ssapp.html` +- `docs/support.html` +- `docs/supported-sites.html` +- `docs/templates.html` +- `docs/tiktok-guide.html` +- `docs/tts.html` +- `docs/youtube-project-setup.html` +- `docs/youtube-websocket-streaming-plan.md` +- `docs/zoom.md` +- `ai.md` +- `seo.md` +- `TOS.md` +- `privacy.html` + +### P0/P1 Event Flow + +- `actions/EventFlowEditor.js` +- `actions/EventFlowSystem.js` +- `actions/interface.js` +- `actions/loader.js` +- `actions/index.html` +- `actions/event-flow-guide.html` +- `actions/state-nodes-guide.html` +- `actions/STATE_NODES_EXPLANATION.md` +- `actions/examples/kick-channel-points-action-flow.json` +- `actions/styles.css` +- `tests/eventflow-compare-property.test.js` +- `tests/eventflow-customjs.test.js` +- `tests/eventflow-play-media-duration.test.js` +- `tests/eventflow-template-vars.test.js` + +### P0/P1 Active Platform Source Code + +These are active source extraction targets. Start with the high-volume platforms, but eventually every active file should get at least a quick pass. + +- `sources/amazon.js` +- `sources/arenasocial.js` +- `sources/autoreload.js` +- `sources/bandlab.js` +- `sources/beamstream.js` +- `sources/bigo.js` +- `sources/bilibili.js` +- `sources/bilibilicom.js` +- `sources/bitchute.js` +- `sources/blaze.js` +- `sources/boltplus.js` +- `sources/bongacams.js` +- `sources/buzzit.js` +- `sources/cam4.js` +- `sources/camsoda.js` +- `sources/capturevideo.js` +- `sources/castr.js` +- `sources/cbox.js` +- `sources/chatroll.js` +- `sources/chaturbate.js` +- `sources/cherrytv.js` +- `sources/chime.js` +- `sources/chzzk.js` +- `sources/cime.js` +- `sources/circle.js` +- `sources/cloudhub.js` +- `sources/cozy.js` +- `sources/crowdcast.js` +- `sources/discord.js` +- `sources/dlive.js` +- `sources/ebay.js` +- `sources/estrim.js` +- `sources/facebook.js` +- `sources/fansly.js` +- `sources/favorited.js` +- `sources/fc2.js` +- `sources/floatplane.js` +- `sources/gala.js` +- `sources/generic.js` +- `sources/goodgame.js` +- `sources/grabvideo.js` +- `sources/instafeed.js` +- `sources/instagram.js` +- `sources/instagramlive.js` +- `sources/jaco.js` +- `sources/joystick.js` +- `sources/kick.js` +- `sources/kick_new.js` +- `sources/kiwiirc.js` +- `sources/kwai.js` +- `sources/lfg.js` +- `sources/linkedin.js` +- `sources/livepush.js` +- `sources/livestorm.js` +- `sources/livestream.js` +- `sources/locals.js` +- `sources/loco.js` +- `sources/meetme.js` +- `sources/meets.js` +- `sources/megaphonetv.js` +- `sources/minnit.js` +- `sources/mixcloud.js` +- `sources/mixlr.js` +- `sources/myfreecams.js` +- `sources/nextcloud.js` +- `sources/nicovideo.js` +- `sources/nimo.js` +- `sources/nonolive.js` +- `sources/odysee.js` +- `sources/on24.js` +- `sources/onlinechurch.js` +- `sources/openai.js` +- `sources/openstreamingplatform.js` +- `sources/owncast.js` +- `sources/parti.js` +- `sources/patreon.js` +- `sources/peertube.js` +- `sources/picarto.js` +- `sources/piczel.js` +- `sources/pilled.js` +- `sources/portal.js` +- `sources/pumpfun.js` +- `sources/quakenet.js` +- `sources/quickchannel.js` +- `sources/README.md` +- `sources/restream.js` +- `sources/retake.js` +- `sources/riverside.js` +- `sources/rokfin.js` +- `sources/roll20.js` +- `sources/rooter.js` +- `sources/rumble.js` +- `sources/rutube.js` +- `sources/sessions.js` +- `sources/shareplay.js` +- `sources/simps.js` +- `sources/slack.js` +- `sources/slido.js` +- `sources/sooplive.js` +- `sources/soulbound.js` +- `sources/steam.js` +- `sources/streamelements.js` +- `sources/streamlabs.js` +- `sources/streamplace.js` +- `sources/stripchat.js` +- `sources/substack.js` +- `sources/teams.js` +- `sources/telegram.js` +- `sources/telegramk.js` +- `sources/tellonym.js` +- `sources/tikfinity.js` +- `sources/tiktok.js` +- `sources/tradingview.js` +- `sources/trovo.js` +- `sources/truffle.js` +- `sources/twitcasting.js` +- `sources/twitch.js` +- `sources/uscreen.js` +- `sources/vdoninja.js` +- `sources/velora.js` +- `sources/vercel.js` +- `sources/verticalpixelzone.js` +- `sources/vimeo.js` +- `sources/vklive.js` +- `sources/vkplay.js` +- `sources/vkvideo.js` +- `sources/vpzone.js` +- `sources/wavevideo.js` +- `sources/webex.js` +- `sources/webinargeek.js` +- `sources/whatnot.js` +- `sources/whatsapp.js` +- `sources/whop.js` +- `sources/wix.js` +- `sources/wix2.js` +- `sources/workplace.js` +- `sources/x.js` +- `sources/xeenon.js` +- `sources/younow.js` +- `sources/youtube.js` +- `sources/youtube_comments.js` +- `sources/youtube_static.js` +- `sources/zapstream.js` +- `sources/zoom.js` + +### P0/P1 WebSocket Source Pages + +- `sources/websocket/bilibili.html` +- `sources/websocket/bilibili.js` +- `sources/websocket/facebook.html` +- `sources/websocket/facebook.js` +- `sources/websocket/irc.html` +- `sources/websocket/irc.js` +- `sources/websocket/joystick.html` +- `sources/websocket/joystick.js` +- `sources/websocket/kick.css` +- `sources/websocket/kick.html` +- `sources/websocket/kick.js` +- `sources/websocket/nostr.html` +- `sources/websocket/nostr.js` +- `sources/websocket/rumble.html` +- `sources/websocket/rumble.js` +- `sources/websocket/socialstreamchat.html` +- `sources/websocket/socialstreamchat.js` +- `sources/websocket/stageten.html` +- `sources/websocket/stageten.js` +- `sources/websocket/streamlabs.html` +- `sources/websocket/streamlabs.js` +- `sources/websocket/twitch.html` +- `sources/websocket/twitch.js` +- `sources/websocket/velora.css` +- `sources/websocket/velora.html` +- `sources/websocket/velora.js` +- `sources/websocket/vpzone.html` +- `sources/websocket/vpzone.js` +- `sources/websocket/websocket-responsive.css` +- `sources/websocket/youtube.css` +- `sources/websocket/youtube.html` +- `sources/websocket/youtube.js` +- `sources/websocket/custom_emotes.json` +- `sources/websocket/emotes.json` + +### P1 AI, TTS, And Advanced Pages + +- `ai.js` +- `ai.md` +- `aioverlay.html` +- `aiprompt.html` +- `cohost.html` +- `cohost-local-qwen-worker.js` +- `cohost-overlay.html` +- `message-ai-export.html` +- `message-ai-export.js` +- `chatbot.html` +- `bot.html` +- `tts.html` +- `tts.js` +- `local-browser-model-worker.js` +- `local-tts-bridge/package.json` +- `local-tts-bridge/README.md` +- `local-tts-bridge/server.cjs` + +### P1/P2 Overlay, Tool, And Integration Pages + +- `actions.html` +- `automix.html` +- `battle.html` +- `chat-overlay.html` +- `chathistory.html` +- `chathistory.js` +- `confetti.html` +- `content.html` +- `createtestmessage.html` +- `credits.html` +- `dashboard.js` +- `emotes.html` +- `events.html` +- `fonts.html` +- `games.html` +- `gif.html` +- `giveaway.html` +- `giveaway-obs-entries.html` +- `hype.html` +- `input.html` +- `leaderboard.html` +- `map.html` +- `meta.html` +- `midimonitor.html` +- `minecraft.html` +- `multi-alerts.html` +- `multi-alerts.js` +- `obs-websocket-test.html` +- `points.js` +- `pointsactions.js` +- `poll.html` +- `reactions.html` +- `recover.html` +- `replaymessages.html` +- `replaymessages.js` +- `sampleapi.html` +- `samplefeatured.html` +- `sampleoverlay.html` +- `scoreboard.html` +- `shop_the_stream.html` +- `simple_api_client.html` +- `spotify.html` +- `spotify.js` +- `spotify-auth-helper.js` +- `spotify-callback.js` +- `spotify-overlay.html` +- `streamelements-importer.html` +- `streamelements-importer.js` +- `streamelements-importer-prompt.md` +- `streamerbot.html` +- `teams.js` +- `ticker.html` +- `timer.html` +- `timer-plan.md` +- `tipjar.html` +- `urleditor.html` +- `vdo.html` +- `waitlist.html` +- `wordcloud.html` + +### P1/P2 Tests And Scripts + +- `scripts/generate-url-parameters.js` +- `scripts/validate-configs.sh` +- `scripts/local-tts-bridge.cjs` +- `scripts/playwright-*.cjs` +- `scripts/aiprompt-*.cjs` +- `tests/*.test.js` +- `tests/*.html` +- `tests/fixtures/*.json` + +### P2/P3 Assets And Historical Context + +Track these by directory unless a page depends on a specific file: + +- `themes/**` +- `games/**` +- `icons/**` +- `media/**` +- `audio/**` +- `translations/**` +- `thirdparty/**` +- `sources/images/**` +- `sources/graveyard/**` +- `sources/static/**` +- `sources/inject/**` + +## Standalone App Repo + +Root: `C:\Users\steve\Code\ssapp` + +Observed candidate resource counts after excluding fallback/build/temp/log output: + +- root files: 45 +- `tests`: 25 +- `resources`: 11 +- `assets`: 11 +- `scripts`: 8 +- `Kokoro-82M-ONNX`: 4 +- `aur`: 4 +- `cloudflare`: 3 +- `tiktok`: 2 +- `tiktok-signing`: 1 + +### P0 Core App Runtime + +- `main.js` +- `preload.js` +- `preload-mock.js` +- `preload-kasada.js` +- `state.js` +- `index.html` +- `main.css` +- `renderer.js` +- `package.json` +- `AGENTS.md` +- `README.md` +- `RELEASE.md` + +### P0/P1 App Platform Handlers + +- `resources/electron-facebook-handler.js` +- `resources/electron-kick-handler.js` +- `resources/electron-media-upload-handler.js` +- `resources/electron-spotify-handler.js` +- `resources/electron-twitch-handler.js` +- `resources/electron-velora-handler.js` +- `resources/electron-vpzone-handler.js` +- `resources/electron-youtube-handler.js` +- `resources/kick-ws-client.js` +- `resources/youtube/proto/stream_list.proto` +- `resources/README.md` + +### P0/P1 TikTok App Behavior + +- `tiktok/connection-manager.js` +- `tiktok/gift-mapping.json` +- `tiktok-signing/electron-signer.js` +- `tiktok-auth.js` +- `tiktok-badges.js` +- `tests/tiktok/authenticated-bootstrap-regression.js` +- `tests/tiktok/auth-ws-e2e.js` +- `tests/tiktok/auto-fuzz-regression.js` +- `tests/tiktok/auto-mode-regression.js` +- `tests/tiktok/chat-emote-regression.js` +- `tests/tiktok/dedupe-replay-regression.js` +- `tests/tiktok/event-capture-regression.js` +- `tests/tiktok/gift-count-regression.js` +- `tests/tiktok/run.js` +- `tests/tiktok/single-active-connection-regression.js` +- `tests/tiktok/social-signal-regression.js` +- `tests/tiktok/validate-403-bugs.js` + +### P1 App Regression And Diagnostic Tests + +- `tests/electron/frame-fallback-diagnostics.js` +- `tests/electron/ipc-scaffold-regression.js` +- `tests/electron/settings-loss-diagnostics.js` +- `tests/electron/settings-rootcause-diagnostics.js` +- `tests/electron/settings-transfer-e2e.js` +- `tests/electron/socialstream-path-security-regression.js` +- `tests/electron/source-url-parsing-regression.js` +- `tests/electron/stability-recovery-diagnostics.js` +- `tests/electron/tts-diagnostics.js` +- `tests/electron/window-state-diagnostics.js` +- `tests/google-oauth-test.js` + +### P2 Build, Release, And Packaging Context + +- `afterPack.js` +- `afterSign.js` +- `customSign.js` +- `CODE_SIGNING.md` +- `CONTRIBUTING.md` +- `scripts/check-submodules.js` +- `scripts/fallbacks/electron-signer.stub.js` +- `scripts/install-custom-electron.js` +- `scripts/installer-user-path.ps1` +- `scripts/patch-deps.js` +- `scripts/submit-virustotal.js` +- `scripts/updateSocialStreamFallback.js` +- `scripts/verify-custom-electron.js` +- `aur/DEPLOYMENT.md` +- `aur/PKGBUILD` +- `aur/README.md` +- `cloudflare/README.md` +- `cloudflare/schema.sql` +- `cloudflare/wrangler.toml` + +### P2/P3 App Assets And Models + +Track by directory unless a feature page needs exact asset behavior: + +- `assets/icons/**` +- `Kokoro-82M-ONNX/**` +- `libs.js` +- `thumbnail.js` +- `youtube.js` +- `tts-worker.js` +- `websocket-monitor.js` +- backup/transfer scripts + +## Stevesbot Support Data + +Root: `C:\Users\steve\Code\stevesbot` + +This repo is support evidence, not product source of truth. + +Observed candidate resource counts after excluding secrets, logs, backups, and replays: + +- `data`: 3,291 files +- `resources`: 81 files +- `skills`: 30 files + +### P0 Curated SSN Support Docs + +- `resources/instructions/social-stream-support.md` +- `resources/learnings/social-stream-ninja-top-issues.md` +- `resources/learnings/support-qa/social-stream-configuration.md` +- `resources/learnings/support-qa/social-stream-qa.md` +- `resources/learnings/support-qa/social-stream-qa-expanded.md` +- `resources/learnings/product-notes/social-stream-architecture.md` +- `resources/learnings/playbooks/playbook-obs-overlay-issues.md` +- `resources/learnings/playbooks/playbook-tiktok-connection.md` +- `resources/learnings/playbooks/rapid-response-decision-tree.md` +- `resources/learnings/playbooks/triage-macros.md` + +### P1 Related Product Support Docs + +Use only where they directly affect SSN support: + +- `resources/learnings/product-notes/electron-capture-notes.md` +- `resources/learnings/product-notes/caption-ninja-notes.md` +- `resources/learnings/cross-product-integration-guide.md` +- `resources/learnings/unresolved-analysis.md` +- `resources/ops/manual-kb-curation-log.md` +- `resources/ops/manual-kb-ops-review.md` +- `resources/ops/playbook.md` + +### P0/P1 SQLite Datasets + +Prefer these over raw support logs for extraction. + +- `resources/knowledge.sqlite` +- `data/sqlite/knowledge.sqlite` +- `data/sqlite/stevesbot.sqlite` +- `data/sqlite/archive.sqlite` + +Observed useful tables/counts: + +- `knowledge.sqlite`: `mined_threads` = 2,264 rows +- `stevesbot.sqlite`: `support_records` = 499 rows +- `stevesbot.sqlite`: `qa_entries` = 358 rows +- `stevesbot.sqlite`: `transcripts` = 13,272 rows +- `archive.sqlite`: `archived_messages` = 47,600 rows + +Observed mined-thread categories: + +- `troubleshooting`: 1,116 +- `how-to`: 341 +- `bug-report`: 260 +- `configuration`: 230 +- `feature-request`: 172 +- `general-discussion`: 70 +- `compatibility`: 44 +- `performance`: 29 +- `other`: 2 + +### P1/P2 JSONL And Export Datasets + +Track these by dataset pattern rather than listing every raw thread file in the main checklist: + +- `data/mined-threads/threads-*.jsonl` +- `data/mined-threads/archive/threads-*.jsonl` +- `data/mined-threads/progress-*.json` +- `data/transcripts/**/*.jsonl` +- `data/exports/qa/qa-export-*.json` +- `data/finetune/draft-training.jsonl` +- `data/finetune/review-training.jsonl` +- `data/finetune/triage-training.jsonl` + +### P2/P3 Attachments + +Use only when a support answer depends on an attached screenshot or image: + +- `data/attachments/**` + +Do not copy personal support images into generated docs. Summarize anonymously. + +## Suggested Query Units For Support Extraction + +Use dataset-level passes instead of raw file-by-file passes for support data. + +Suggested units: + +- `mined_threads where products_json/searchable_text mentions Social Stream or SSN` +- `mined_threads by category` +- `mined_threads by platform keyword: TikTok, YouTube, Kick, Twitch, Rumble, Facebook, Instagram, OBS` +- `support_records where product_id or searchable_text indicates social-stream` +- `qa_entries filtered for social stream terms` +- `archived_messages FTS only for exact symptom confirmation` + +## Refresh Commands + +Use these commands to refresh this manifest later. + +```powershell +cd C:\Users\steve\Code\social_stream +rg --files -g '!node_modules/**' -g '!.git/**' -g '!docs/agents/**' | Sort-Object + +cd C:\Users\steve\Code\ssapp +rg --files -g '!node_modules/**' -g '!.git/**' -g '!resources/social_stream_fallback/**' -g '!dist/**' -g '!tmp/**' | Sort-Object + +cd C:\Users\steve\Code\stevesbot +rg --files -g '!resources/secrets/**' -g '!logs/**' -g '!data/backups/**' -g '!data/replays/**' | Sort-Object +``` diff --git a/docs/agents/03-extension-architecture.md b/docs/agents/03-extension-architecture.md new file mode 100644 index 000000000..28c20ed88 --- /dev/null +++ b/docs/agents/03-extension-architecture.md @@ -0,0 +1,108 @@ +# Extension Architecture + +Status: backbone extraction pass. Usable for orientation, not final-grade. + +## Purpose + +This page documents the Chrome extension runtime: manifest, service worker, background page, popup/settings UI, source/content scripts, storage, permissions, and message routing. + +## Source Anchors + +- `social_stream/manifest.json` +- `social_stream/service_worker.js` +- `social_stream/background.html` +- `social_stream/background.js` +- `social_stream/popup.html` +- `social_stream/popup.js` +- `social_stream/sources/**/*.js` +- `social_stream/providers/**/*` +- `social_stream/shared/**/*` +- `social_stream/settings/*` + +## Runtime Shape + +The extension is a Manifest V3 Chrome extension. The runtime is split across three main layers: + +- `service_worker.js`: transient MV3 service worker that receives extension messages, checks extension state, opens or recovers the hidden background page, and queues messages while that page is loading. +- `background.html` plus `background.js`: long-running extension control page used for settings, sockets, routing, overlay/dock distribution, API handling, and platform integration behavior that should survive beyond a single content-script message. +- Source/content scripts: platform-specific scripts declared in `manifest.json` or loaded from the extension, usually under `sources/`, `providers/`, `shared/`, or `thirdparty/`. + +`popup.html` and `popup.js` are the main user-facing extension popup. `settings/options.html` is the options UI declared in `manifest.json`. + +## Manifest Facts + +Confirmed from `manifest.json`: + +- Current manifest version is MV3. +- `background.service_worker` points to `service_worker.js`. +- The extension action popup is `popup.html`. +- The options page is `settings/options.html`. +- Permissions include `webNavigation`, `notifications`, `storage`, `debugger`, `tabs`, `scripting`, `activeTab`, `tabCapture`, and `identity`. +- Web-accessible resources expose provider cores, shared utilities, vendor scripts, browser model files, workers, and selected UI/runtime assets to extension pages or injected scripts. +- Content scripts are mapped to many platform URL patterns. This manifest is the first source to check when a platform page is not being captured at all. +- CSP is restrictive and extension-local: `script-src 'self' 'wasm-unsafe-eval'; object-src 'self'`. + +## Service Worker Responsibilities + +`service_worker.js` exists because MV3 needs a service worker entry point, but its own comments warn that a service worker can be stopped after a few minutes and local variables can be lost. The design therefore keeps durable routing work in `background.html` / `background.js`. + +Confirmed responsibilities: + +- Track `backgroundPageTabId` and whether the background page has loaded. +- Create or reuse a hidden pinned `background.html` tab with `chrome.tabs.create({ url: chrome.runtime.getURL("background.html"), active: false, pinned: true })`. +- Queue messages while the background page is loading. +- Retry background-page recovery with cooldown logic. +- Read extension on/off state from `chrome.storage.sync` first, then `chrome.storage.local`. +- Read a settings snapshot using `streamID`, `password`, and `state` from `chrome.storage.sync`, plus `settings` from `chrome.storage.local`. +- Route normal source messages to the background page. +- Permit a narrow set of settings/write commands even while the extension is disabled. +- Handle helper commands such as `checkBackgroundPage`, `injectCustomSource`, `openEventFlowEditor`, and `captureTabAudio`. +- On install/startup, open the background page unless stored state is false, then periodically check the background page. + +## Background Page Responsibilities + +`background.js` is the main extension brain. It loads or migrates settings, owns socket connections, processes incoming source messages, sends data to docks and overlays, and accepts some remote/API commands. + +Confirmed responsibilities: + +- Load `settings.json` override when present, otherwise load saved settings. +- In extension mode, read `streamID`, `password`, and `state` from `chrome.storage.sync`. +- In extension mode, read `settings` and `returningBeepHintShown` from `chrome.storage.local`. +- Migrate older storage layouts by moving `streamID`, `password`, and `state` into sync storage while keeping the larger `settings` object in local storage. +- Open the dock socket when `settings.server2` or `settings.server3` is enabled and the extension is on. +- Open the API socket when `settings.socketserver` is enabled and the extension is on. +- Use local WebSocket endpoint `ws://127.0.0.1:3000` when `localserver` is enabled, otherwise use hosted `wss://io.socialstream.ninja/dock` and `wss://io.socialstream.ninja/api`. +- Join the dock socket with `{ join: streamID, out: 4, in: 3 }`. +- Join the API socket with `{ join: streamID, out: 2, in: 1 }`. +- Handle inbound API actions such as `sendChat`, `sendEncodedChat`, `blockUser`, `eventFlowEvent`, and `extContent`. +- Send dock/overlay data through server fallback, VDO.Ninja/ninjaBridge paths, or VDO iframe `postMessage` fallback depending on settings and connection state. + +## Storage Model + +Confirmed current split: + +- `chrome.storage.sync`: `streamID`, `password`, `state` +- `chrome.storage.local`: larger `settings` object and local-only flags such as `returningBeepHintShown` + +This split matters for support answers. A user can have a valid session ID but broken local settings, or vice versa. It also matters when comparing Chrome extension behavior with the standalone app, which mirrors and repairs settings differently. + +## Message Routing Summary + +Typical extension flow: + +1. A platform content script extracts a chat/event payload. +2. The content script sends it to the extension runtime. +3. `service_worker.js` verifies state and forwards or queues the message. +4. `background.html` / `background.js` processes settings, filters, commands, and integrations. +5. `background.js` sends the normalized output to dock, overlays, API clients, or P2P/server transports. + +Important distinction: the service worker is a router/recovery layer; `background.js` is where most durable product behavior belongs. + +## Extraction Notes + +This pass focused on high-level architecture. Deeper passes should inspect: + +- Exact `chrome.runtime.onMessage` command names and compatibility paths. +- Exact popup/settings save path in `popup.js` and `settings/*`. +- Platform-specific script injection rules and any source scripts that bypass the standard path. +- Which API inbound actions are stable public contract versus internal compatibility. diff --git a/docs/agents/04-standalone-app-architecture.md b/docs/agents/04-standalone-app-architecture.md new file mode 100644 index 000000000..c5cfb4529 --- /dev/null +++ b/docs/agents/04-standalone-app-architecture.md @@ -0,0 +1,111 @@ +# Standalone App Architecture + +Status: backbone extraction pass. Usable for orientation, not final-grade. + +## Purpose + +This page documents how the Electron standalone app works, how it loads Social Stream source files, and where it differs from the Chrome extension. + +## Source Anchors + +- `ssapp/main.js` +- `ssapp/preload.js` +- `ssapp/preload-mock.js` +- `ssapp/state.js` +- `ssapp/index.html` +- `ssapp/renderer.js` +- `ssapp/resources/electron-*-handler.js` +- `ssapp/resources/kick-ws-client.js` +- `ssapp/tiktok/connection-manager.js` +- `ssapp/tests/electron/*` + +Do not use `ssapp/resources/social_stream_fallback` as source documentation material during normal extraction. The project instructions say Social Stream source edits and runtime source-of-truth work belong in `C:\Users\steve\Code\social_stream`; the fallback folder is disposable build/update output. + +## Runtime Shape + +The standalone app is an Electron app that wraps SSN workflows and provides extension-like APIs to Social Stream source pages. It is not just a static copy of the extension. The important layers are: + +- `main.js`: Electron main process, window creation, app menu/actions, source-root loading, local source validation, state backup/repair, IPC, OAuth handler wiring, and app-specific platform helpers. +- `preload.js`: secure bridge exposed to pages as `window.ninjafy` when context isolation is enabled, plus fallback direct assignment when it is not. +- `state.js`: renderer-side state model for sources, groups, global settings, migration from older localStorage settings, WebSocket support detection, and session binding. +- `renderer.js` / `index.html`: app UI for managing source windows, groups, sessions, and source behavior. +- `resources/electron-*-handler.js`: OAuth and platform-specific app handlers. +- `resources/kick-ws-client.js`, `tiktok/*`, `tiktok-signing/*`: app-side platform connection support. + +## Source Loading + +`main.js` contains helpers for loading Social Stream source files from local folders or zip imports. Confirmed behavior: + +- A valid Social Stream source root must include `manifest.json`, `background.html`, `popup.html`, `sources/twitch.js`, and a manifest with `content_scripts`. +- Folder import validates the chosen root before storing it. +- Zip import extracts to an app data location, searches for the preferred GitHub zip root, validates it, stores the local source path, and reloads. +- Source paths can be represented as file URLs, so path/file URL conversion helpers are part of the app behavior. +- Clearing a saved local source path removes `localSourcePath`, clears the runtime source argument, and queues a toast. + +Support implication: if app source loading fails, verify the selected folder is the actual Social Stream repo/root, not a parent folder, zip wrapper folder, or generated fallback bundle. + +## Preload Bridge + +`preload.js` exposes `window.ninjafy` as the app's extension-compatibility bridge. This lets Social Stream source code call app-provided APIs instead of Chrome extension APIs. + +Confirmed bridge areas: + +- Authenticated `sendMessage` path through IPC using an app auth token. +- `getAuthToken`, injected-script flags, and source-window config helpers. +- `onSendToTab`, `onPostMessage`, `onWebSocketMessage`, and device-list callbacks. +- File stream helpers, save dialogs, append-to-file behavior, and TTS helpers. +- No-CORS/fetch helpers such as Rumble JSON fetch support. +- OAuth methods for YouTube, Twitch, Facebook, Velora, Kick, and VPZone. +- Media upload helpers. +- Kick WebSocket start/stop/status/event methods. +- `ssappLocale`, `ssappFallback`, `ssappEnvironment`, and `ssappCustomJs` exposures. + +Support implication: when a workflow works in Chrome but not in the standalone app, check whether it depends on a browser extension API, a login/cookie context, or an app preload bridge method. + +## State And Persistence + +`state.js` stores the app UI/runtime state in localStorage under `socialStreamState`. It serializes `sources` and `groups` maps and restores them on startup. + +Confirmed global fields include: + +- `betaMode` +- TikTok mode fields such as `forceTikTokClassic`, `preferTikTokLegacy`, `tiktokModeExplicitlySelected`, and `lastTikTokMode` +- YouTube auto-add and cleanup settings +- current page/root order +- source session bindings + +`state.js` also migrates older localStorage `settings` into source entries. It detects WebSocket support by checking known targets and by inspecting the Social Stream manifest content scripts for `websocket/.js`. + +`main.js` has additional settings preservation logic. It gathers cached state candidates from disk backups, electron-store backups, and localStorage backups; scores candidates; avoids overwriting richer settings with partial settings; and mirrors cached state to localStorage keys such as `settings`, `streamID`, `password`, `state`, `ssninja_stream_id`, and `ssninja_state`. + +Support implication: settings loss is an app-specific high-priority documentation area because state can exist in several backup/mirror locations. + +## Session Binding + +The app remembers source-to-session associations through `sessionBindings` in global state. It builds keys from source details such as target, group, username, channel, video ID, URL, or explicit key. Auto/default/blank sessions are not remembered. + +This matters when documenting: + +- Why a source opens into a remembered session. +- Why default/blank sessions may not be restored. +- How moving sources between groups or changing URLs can affect remembered sessions. + +## App Vs Extension Differences + +Key differences to keep explicit in support docs: + +- The Chrome extension runs in the user's browser session. The app runs in Electron and may hit sign-in or embedded-browser restrictions that Chrome does not. +- The extension uses `chrome.storage.sync` plus `chrome.storage.local`. The app uses localStorage, electron-store backup, disk backup files, and app repair logic. +- The extension depends on MV3 service worker plus a hidden background page. The app depends on Electron main/preload/renderer IPC. +- The app can load source code from local folders/zips; the extension uses packaged extension files. +- OAuth and platform auth can be app-specific and may not match the Chrome extension path. + +## Extraction Notes + +Deeper passes should inspect: + +- Exact IPC channels between `main.js`, `preload.js`, and renderer/source windows. +- OAuth handler behavior by platform. +- TikTok mode selection, signing fallback, and regression tests. +- Settings repair tests under `ssapp/tests/electron/*`. +- User-facing source window lifecycle in `renderer.js`. diff --git a/docs/agents/05-message-flow-and-event-contracts.md b/docs/agents/05-message-flow-and-event-contracts.md new file mode 100644 index 000000000..f3761346b --- /dev/null +++ b/docs/agents/05-message-flow-and-event-contracts.md @@ -0,0 +1,129 @@ +# Message Flow And Event Contracts + +Status: backbone extraction pass. Usable for orientation, not final-grade. + +## Purpose + +This page is the agent-facing source for how messages move through SSN and what payload shapes downstream pages should expect. + +## Source Anchors + +- `social_stream/docs/event-reference.html` +- `social_stream/about.md` +- `social_stream/api.md` +- `social_stream/background.js` +- `social_stream/dock.html` +- `social_stream/featured.html` +- `social_stream/sources/*.js` +- `ssapp/preload.js` +- `ssapp/main.js` + +## Product Flow + +The high-level flow confirmed from `about.md`: + +1. A platform source captures chat, events, or source state. +2. The source sends normalized data to the extension/app background process. +3. The background process applies settings, routing, filtering, and integrations. +4. Data is distributed through P2P, hosted WebSocket servers, local WebSocket server mode, HTTP/API paths, or direct app/extension messaging. +5. Dock/dashboard views receive messages and can send moderation/control actions back. +6. Overlay pages such as featured chat, alerts, waitlists, polls, games, and custom overlays consume the same session-routed data. +7. External apps can use API/WebSocket/HTTP/SSE paths depending on feature and settings. + +Session ID is the main routing key. Password is optional but can affect access/control paths. + +## Extension Message Flow + +Typical extension path: + +1. A content/source script runs in a platform page and extracts data. +2. The script sends a runtime message. +3. `service_worker.js` checks whether the extension is enabled and whether `background.html` is ready. +4. If needed, the service worker creates or reuses a pinned inactive `background.html` tab. +5. Messages are queued while the background page is loading. +6. `background.js` receives the message, applies settings, and distributes it to docks, overlays, sockets, or API clients. + +Important distinction: `service_worker.js` is intentionally a lightweight router/recovery layer because MV3 workers are temporary. Long-lived behavior belongs in `background.js`. + +## Standalone App Message Flow + +Typical standalone app path: + +1. A Social Stream source page or source window calls `window.ninjafy`. +2. `preload.js` authenticates/normalizes the call and sends it through Electron IPC. +3. `main.js` handles app-side routing, platform helpers, auth, and window messaging. +4. Renderer/app state in `state.js` tracks source windows, groups, sessions, and source-specific settings. +5. Social Stream background/dock/overlay logic receives data through app bridge paths that imitate extension behavior where possible. + +Support implication: "works in extension but not app" often means the failure is in Electron login context, preload bridge behavior, IPC, app state, or app-specific platform handling rather than the shared overlay/dock code. + +## Dock, Overlay, And API Distribution + +`background.js` has multiple output paths. Confirmed from the first pass: + +- Dock/server fallback socket: + - Local mode: `ws://127.0.0.1:3000` + - Hosted mode: `wss://io.socialstream.ninja/dock` + - Join shape: `{ join: streamID, out: 4, in: 3 }` +- API socket: + - Local mode: `ws://127.0.0.1:3000` + - Hosted mode: `wss://io.socialstream.ninja/api` + - Join shape: `{ join: streamID, out: 2, in: 1 }` +- P2P/ninjaBridge path: + - Sends `overlayNinja` payloads to known receiver labels such as `dock`, `aioverlay`, `cohost`, and `tipjar`. + - Can broadcast when no specific receiver is available. +- VDO iframe fallback: + - Uses `postMessage` with a `sendData` wrapper when needed. + +These transport details should be documented separately from payload shape. The same event payload may travel through different transports depending on settings and connection state. + +## Event Contract + +`docs/event-reference.html` is the canonical event vocabulary. The current rule for future docs should be: + +- Put standard event fields in the event reference. +- Put experimental, feature-specific, or integration-specific details under `meta` unless they are promoted to stable top-level fields. +- Treat platform-specific events as source-dependent unless the event reference says they are normalized. +- Note whether a feature requires WebSocket mode, DOM/source capture mode, or either. + +Confirmed event-reference guidance: + +- Stream events can be hidden with `&hideevents`, `&hideallevents`, or filtered with `&filterevents=...`. +- Most YouTube, Twitch, and Kick stream events require WebSocket mode. +- DOM mode is mostly chat/viewer/limited system events, with gift/donation behavior varying by source. +- `meta.messageId` is used for source-control delete synchronization. +- Event Flow can mark `meta.featured = true`. +- AI/cohost overlay commands use action payloads such as `{ action: "aiOverlay", target, meta }` or `{ action: "cohostOverlay", target, meta }`. + +## Inbound Control Actions + +The first pass found `background.js` handling inbound actions from the API/dock paths, including: + +- `sendChat` +- `sendEncodedChat` +- `blockUser` +- `eventFlowEvent` +- `extContent` +- lightweight status/request actions such as `getHype` + +These need an intense pass before being documented as stable public API. For now, treat them as confirmed code paths, not fully specified contracts. + +## Compatibility Rules For Custom Overlays + +Until a field-level pass is complete, custom overlay docs should follow these rules: + +- Consume documented fields from `docs/event-reference.html`. +- Read optional behavior from `meta` defensively. +- Do not assume every platform sends every event type. +- Do not assume the transport path. A payload may arrive through P2P, hosted WebSocket, local WebSocket, iframe messaging, or app bridge. +- Use session ID routing consistently and document password requirements where a control path needs them. + +## Extraction Notes + +Deeper passes should build: + +- Field-by-field chat payload contract. +- Event-type table for YouTube, TikTok, Twitch, Kick, Facebook, Instagram, Rumble, Discord, and generic/custom sources. +- API inbound command table with source references. +- Deletion/moderation/featured-message lifecycle. +- OBS/browser-source examples that show the same message through dock and featured overlay. diff --git a/docs/agents/06-settings-sessions-and-storage.md b/docs/agents/06-settings-sessions-and-storage.md new file mode 100644 index 000000000..ec6625a08 --- /dev/null +++ b/docs/agents/06-settings-sessions-and-storage.md @@ -0,0 +1,110 @@ +# Settings Sessions And Storage + +Status: backbone extraction pass. Usable for orientation, not final-grade. + +## Purpose + +This page documents session IDs, passwords, storage, settings import/export, URL parameters, and how settings differ between extension and standalone app. + +## Source Anchors + +- `social_stream/popup.html` +- `social_stream/popup.js` +- `social_stream/settings/*` +- `social_stream/shared/config/settingsDefinitions.js` +- `social_stream/shared/config/urlParameters.js` +- `social_stream/parameters.md` +- `social_stream/background.js` +- `social_stream/service_worker.js` +- `ssapp/state.js` +- `ssapp/main.js` +- `ssapp/tests/electron/settings-*.js` +- `stevesbot/resources/instructions/social-stream-support.md` + +## Session ID + +Session ID is the central routing value for docks, overlays, APIs, and source windows. Most support flows should verify: + +- The source/capture side and receiving page use the same session ID. +- The user did not accidentally open an old dock/overlay URL with a stale session. +- The app/extension has the session saved in the expected storage layer. +- OBS browser sources were refreshed after a session change. + +## Password + +Password is optional, but it can matter for control paths and protected sessions. Documentation should avoid saying password is always required. Instead: + +- For basic display-only overlays, first verify matching session ID. +- For API/control/moderation paths, check whether the path requires password or admin/control credentials. +- If a user reports receiving messages but not being able to control/moderate/send, password mismatch is a likely category. + +## Chrome Extension Storage + +Confirmed from `service_worker.js` and `background.js`: + +- `chrome.storage.sync` stores: + - `streamID` + - `password` + - `state` +- `chrome.storage.local` stores: + - the larger `settings` object + - local flags such as `returningBeepHintShown` + +The service worker reads `state` from sync first, then local as fallback. Its settings snapshot combines sync values with local settings. + +`background.js` migrates older storage layouts by moving `streamID`, `password`, and `state` to sync storage while keeping `settings` in local storage. + +Support implication: extension settings can be partially valid. For example, a session ID can exist in sync storage while a local settings object is stale, missing, or corrupted. + +## Standalone App Storage + +Confirmed from `state.js` and `main.js`: + +- `state.js` stores app UI/runtime state in localStorage under `socialStreamState`. +- `sources` and `groups` are serialized as arrays and restored as Maps. +- App global fields include TikTok mode preferences, YouTube auto-add/cleanup behavior, current page, root order, and session bindings. +- `state.js` migrates older localStorage `settings` into source entries. +- `main.js` reads and writes cached state across disk backups, electron-store backup, and localStorage backup. +- `main.js` mirrors settings/session values into localStorage keys including `settings`, `streamID`, `password`, `state`, `ssninja_stream_id`, and `ssninja_state`. +- On quit, app localStorage can be backed up into electron-store as `localStorageBackup`. + +Support implication: app settings-loss troubleshooting needs a separate page. It is not the same as clearing Chrome extension storage. + +## Session Binding In The App + +`state.js` keeps `sessionBindings` in global state. Bindings remember which session should be used for a source based on stable source identity fields. + +Confirmed behavior: + +- Binding keys can use target, group, username, channel, video ID, URL, or explicit key. +- Auto/default/blank sessions are not remembered. +- `addSource` applies remembered session bindings when creating source entries. +- Updating global state writes compatibility localStorage keys for selected global preferences. + +Documentation should explain this in user terms: the app may remember the session for a source, but it intentionally avoids remembering vague/default sessions. + +## URL Parameters + +`parameters.md` and `shared/config/urlParameters.js` still need a heavy extraction pass. Until that pass is complete: + +- Treat URL parameters as source-backed only when they are listed in `parameters.md` or generated/shared config. +- For common support answers, document the exact page plus parameter, such as dock parameters separately from featured overlay parameters. +- Avoid mixing app storage settings with one-off URL parameters. A URL parameter may affect only that browser source/page instance. + +## Import, Export, And Backup Notes + +Support history says settings loss is common enough that agents should recommend exporting settings before risky actions. Current confirmed docs should say: + +- For extension users, do not advise uninstalling the extension as a casual update step because uninstalling can remove extension storage. +- For standalone app users, settings are more complex and may involve app backups/mirrors; preserve files before clearing app data. +- If a user is switching between extension and app, verify which storage model they are actually using before giving reset instructions. + +## Extraction Notes + +Deeper passes should build: + +- Exact settings export/import workflow from popup/settings UI. +- Exact storage key table with where each key lives. +- Settings-loss recovery guide for extension and app separately. +- URL parameter catalog grouped by page. +- Tests-backed app settings repair behavior from `ssapp/tests/electron/settings-*.js`. diff --git a/docs/agents/07-overlays-and-pages/custom-overlays.md b/docs/agents/07-overlays-and-pages/custom-overlays.md new file mode 100644 index 000000000..b8f8089db --- /dev/null +++ b/docs/agents/07-overlays-and-pages/custom-overlays.md @@ -0,0 +1,29 @@ +# Custom Overlays + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document how custom overlays consume SSN messages and how users can style or build their own pages safely. + +## Source Anchors + +- `social_stream/docs/customoverlays.md` +- `social_stream/docs/event-reference.html` +- `social_stream/sampleoverlay.html` +- `social_stream/samplefeatured.html` +- `social_stream/themes/**` + +## Starter Notes + +Custom overlays commonly use either WebSocket/API connection methods or the hidden VDO.Ninja iframe bridge. Existing repo instructions prefer preserving payload structure and using URL-driven CSS/settings when possible. + +## Planned Sections + +- Message listener patterns +- VDO.Ninja bridge +- WebSocket API +- CSS customization +- Payload compatibility +- Examples +- Common mistakes diff --git a/docs/agents/07-overlays-and-pages/dock.md b/docs/agents/07-overlays-and-pages/dock.md new file mode 100644 index 000000000..1237473e4 --- /dev/null +++ b/docs/agents/07-overlays-and-pages/dock.md @@ -0,0 +1,29 @@ +# Dock Page + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document `dock.html`, the main dashboard/control page for viewing, filtering, selecting, sending, pinning, queueing, and routing messages. + +## Source Anchors + +- `social_stream/dock.html` +- `social_stream/api.md` +- `social_stream/parameters.md` +- `social_stream/docs/customoverlays.md` +- `stevesbot/resources/instructions/social-stream-support.md` + +## Starter Notes + +Support guidance says a blank or white `dock.html` can be expected if the user does not understand it is a dashboard. It needs a matching `?session=` value to receive traffic. + +## Planned Sections + +- Required URL parameters +- Dashboard vs overlay behavior +- Manual featuring and autoshow +- Queue/pin/sync behavior +- TTS and OBS controls +- API actions +- Common support issues diff --git a/docs/agents/07-overlays-and-pages/featured.md b/docs/agents/07-overlays-and-pages/featured.md new file mode 100644 index 000000000..d9e4e02cb --- /dev/null +++ b/docs/agents/07-overlays-and-pages/featured.md @@ -0,0 +1,28 @@ +# Featured Overlay + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document `featured.html`, the overlay that displays selected or auto-selected chat messages. + +## Source Anchors + +- `social_stream/featured.html` +- `social_stream/api.md` +- `social_stream/parameters.md` +- `social_stream/docs/customoverlays.md` +- `social_stream/themes/featured-styles/**` + +## Starter Notes + +Support history says users can confuse a white or empty browser view with a broken overlay. The featured page often has transparent background behavior intended for OBS. + +## Planned Sections + +- Connection methods +- Manual vs autoshow +- Styling and themes +- OBS browser source setup +- API actions +- Troubleshooting blank/transparent output diff --git a/docs/agents/07-overlays-and-pages/index.md b/docs/agents/07-overlays-and-pages/index.md new file mode 100644 index 000000000..75144dbd9 --- /dev/null +++ b/docs/agents/07-overlays-and-pages/index.md @@ -0,0 +1,24 @@ +# Overlays And Pages Index + +Status: framework only. Detailed extraction not started. + +## Purpose + +This section covers SSN pages users open in browsers, OBS, the extension, or the standalone app. + +## Pages + +- `dock.md` +- `featured.md` +- `multi-alerts.md` +- `waitlist-polls-games.md` +- `custom-overlays.md` + +## Source Anchors + +- `social_stream/dock.html` +- `social_stream/featured.html` +- `social_stream/docs/customoverlays.md` +- `social_stream/api.md` +- `social_stream/parameters.md` +- `social_stream/themes/**` diff --git a/docs/agents/07-overlays-and-pages/multi-alerts.md b/docs/agents/07-overlays-and-pages/multi-alerts.md new file mode 100644 index 000000000..b0080487f --- /dev/null +++ b/docs/agents/07-overlays-and-pages/multi-alerts.md @@ -0,0 +1,26 @@ +# Multi Alerts + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document the multi-alerts page and how alert-like events are routed and displayed separately from normal chat. + +## Source Anchors + +- `social_stream/multi-alerts.html` +- `social_stream/multi-alerts.js` +- `social_stream/popup.html` +- `social_stream/docs/event-reference.html` + +## Starter Notes + +Alert-style events may include follows, subs, raids, donations, memberships, or other platform events. Some settings can route events away from `dock.html` and into alert overlays. + +## Planned Sections + +- Event types consumed +- Setup and URL parameters +- Interaction with popup settings +- Styling and layout +- Common failures diff --git a/docs/agents/07-overlays-and-pages/waitlist-polls-games.md b/docs/agents/07-overlays-and-pages/waitlist-polls-games.md new file mode 100644 index 000000000..6c22aba7f --- /dev/null +++ b/docs/agents/07-overlays-and-pages/waitlist-polls-games.md @@ -0,0 +1,30 @@ +# Waitlist Polls And Games + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document pages that turn chat into interactive workflows: waitlists, polls, timers, giveaways, games, battles, scores, and related tools. + +## Source Anchors + +- `social_stream/waitlist.html` +- `social_stream/poll.html` +- `social_stream/timer.html` +- `social_stream/giveaway.html` +- `social_stream/battle.html` +- `social_stream/games/**` +- `social_stream/api.md` + +## Starter Notes + +These pages are feature-specific consumers of the same session/message system. API docs already include some controls for waitlist, poll, timer, and battle behavior. + +## Planned Sections + +- Page inventory +- Setup requirements +- Chat commands or triggers +- API controls +- OBS usage +- Support issues diff --git a/docs/agents/08-platform-sources/discord.md b/docs/agents/08-platform-sources/discord.md new file mode 100644 index 000000000..aefc22649 --- /dev/null +++ b/docs/agents/08-platform-sources/discord.md @@ -0,0 +1,25 @@ +# Discord Source + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document Discord source behavior and how it differs from Discord support-data sources in `stevesbot`. + +## Source Anchors + +- `social_stream/sources/discord.js` +- `social_stream/docs/event-reference.html` +- `stevesbot/data/sqlite/archive.sqlite` + +## Starter Notes + +Discord appears both as an SSN source and as the historical support data origin. Keep those separate: Discord source docs should describe SSN capture behavior, while support KB docs should describe mined support history. + +## Planned Sections + +- Discord as platform source +- Message fields +- Attachments/media +- Common source failures +- Difference from support archive data diff --git a/docs/agents/08-platform-sources/facebook.md b/docs/agents/08-platform-sources/facebook.md new file mode 100644 index 000000000..e3f6e7010 --- /dev/null +++ b/docs/agents/08-platform-sources/facebook.md @@ -0,0 +1,27 @@ +# Facebook Source + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document Facebook capture behavior, login requirements, app OAuth helper, and support issues. + +## Source Anchors + +- `social_stream/sources/facebook.js` +- `social_stream/sources/websocket/facebook.html` +- `social_stream/sources/websocket/facebook.js` +- `ssapp/resources/electron-facebook-handler.js` +- `stevesbot/resources/instructions/social-stream-support.md` + +## Starter Notes + +Existing support guidance says Facebook may need viewer mode rather than publisher mode, and network/device context can matter. + +## Planned Sections + +- Standard capture setup +- WebSocket source behavior +- Login/OAuth in app +- Viewer vs publisher mode +- Common failures diff --git a/docs/agents/08-platform-sources/generic-and-custom-sources.md b/docs/agents/08-platform-sources/generic-and-custom-sources.md new file mode 100644 index 000000000..e1367b23f --- /dev/null +++ b/docs/agents/08-platform-sources/generic-and-custom-sources.md @@ -0,0 +1,30 @@ +# Generic And Custom Sources + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document generic source capture, custom source patterns, and how new sources should be added or debugged. + +## Source Anchors + +- `social_stream/sources/generic.js` +- `social_stream/sources/README.md` +- `social_stream/custom_sample.js` +- `social_stream/custom_actions.js` +- `social_stream/sample_wss_source.html` +- `social_stream/docs/customoverlays.md` +- `social_stream/README.md` + +## Starter Notes + +SSN supports many platform-specific scripts plus generic/custom entry points. This page should bridge user customization and developer source-adding guidance. + +## Planned Sections + +- Generic capture +- Custom scripts +- WSS source examples +- Adding a source +- Debugging capture selectors +- Compatibility with extension and app diff --git a/docs/agents/08-platform-sources/index.md b/docs/agents/08-platform-sources/index.md new file mode 100644 index 000000000..60f660561 --- /dev/null +++ b/docs/agents/08-platform-sources/index.md @@ -0,0 +1,28 @@ +# Platform Sources Index + +Status: framework only. Detailed extraction not started. + +## Purpose + +This section tracks platform-specific source capture behavior. + +## High-Priority Pages + +- `youtube.md` +- `tiktok.md` +- `twitch.md` +- `kick.md` +- `facebook.md` +- `instagram.md` +- `rumble.md` +- `discord.md` +- `generic-and-custom-sources.md` + +## Source Anchors + +- `social_stream/sources/*.js` +- `social_stream/sources/websocket/*` +- `social_stream/providers/*` +- `ssapp/resources/electron-*-handler.js` +- `ssapp/tiktok/*` +- `stevesbot/resources/learnings/social-stream-ninja-top-issues.md` diff --git a/docs/agents/08-platform-sources/instagram.md b/docs/agents/08-platform-sources/instagram.md new file mode 100644 index 000000000..145301477 --- /dev/null +++ b/docs/agents/08-platform-sources/instagram.md @@ -0,0 +1,25 @@ +# Instagram Source + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document Instagram and Instagram Live source behavior. + +## Source Anchors + +- `social_stream/sources/instagram.js` +- `social_stream/sources/instagramlive.js` +- `social_stream/sources/instafeed.js` +- `stevesbot/data/sqlite/knowledge.sqlite` + +## Starter Notes + +Instagram has multiple source files and likely distinct capture flows for feed and live behavior. Detailed extraction is needed before giving confident setup advice. + +## Planned Sections + +- Source differences +- Login/session assumptions +- Capture behavior +- Common support issues diff --git a/docs/agents/08-platform-sources/kick.md b/docs/agents/08-platform-sources/kick.md new file mode 100644 index 000000000..74d1921bf --- /dev/null +++ b/docs/agents/08-platform-sources/kick.md @@ -0,0 +1,32 @@ +# Kick Source + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document Kick capture modes, auth, WebSocket bridge behavior, channel points/rewards, and support issues. + +## Source Anchors + +- `social_stream/sources/kick.js` +- `social_stream/sources/kick_new.js` +- `social_stream/sources/websocket/kick.html` +- `social_stream/sources/websocket/kick.js` +- `social_stream/providers/kick/core.js` +- `ssapp/resources/electron-kick-handler.js` +- `ssapp/resources/kick-ws-client.js` +- `social_stream/docs/kick-channel-points-event-flow.md` + +## Starter Notes + +Support guidance says Kick often requires pop-out chat and sign-in. Captcha or "verifying human" flows can be platform-side and may affect the standalone app differently than Chrome. + +## Planned Sections + +- Standard source +- WebSocket source +- App bridge behavior +- OAuth/sign-in +- Channel points/rewards +- Event Flow setup +- Common failures diff --git a/docs/agents/08-platform-sources/rumble.md b/docs/agents/08-platform-sources/rumble.md new file mode 100644 index 000000000..c52295478 --- /dev/null +++ b/docs/agents/08-platform-sources/rumble.md @@ -0,0 +1,26 @@ +# Rumble Source + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document Rumble source setup, popup URL formats, WebSocket source behavior, and known support issues. + +## Source Anchors + +- `social_stream/sources/rumble.js` +- `social_stream/sources/websocket/rumble.html` +- `social_stream/sources/websocket/rumble.js` +- `stevesbot/resources/learnings/social-stream-ninja-top-issues.md` + +## Starter Notes + +Support summaries mention exact Rumble URL formats and verification loops. These claims need source verification and current-code checks. + +## Planned Sections + +- Popup chat URL +- Live page URL fallback +- WebSocket source +- Verification/user-agent issues +- Common failures diff --git a/docs/agents/08-platform-sources/tiktok.md b/docs/agents/08-platform-sources/tiktok.md new file mode 100644 index 000000000..3699f0e0f --- /dev/null +++ b/docs/agents/08-platform-sources/tiktok.md @@ -0,0 +1,32 @@ +# TikTok Source + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document TikTok standard mode, WebSocket mode, signing, app-specific connection management, and common support problems. + +## Source Anchors + +- `social_stream/sources/tiktok.js` +- `ssapp/tiktok/connection-manager.js` +- `ssapp/tiktok-signing/electron-signer.js` +- `ssapp/tiktok-auth.js` +- `ssapp/tiktok-badges.js` +- `ssapp/tests/tiktok/*` +- `social_stream/docs/tiktok-guide.html` +- `stevesbot/resources/learnings/playbooks/playbook-tiktok-connection.md` + +## Starter Notes + +Support data repeatedly identifies TikTok as fragile. Known themes include API changes, standard mode throttling when hidden/minimized, WebSocket mode tradeoffs, duplicate gift behavior, and live/user ID setup mistakes. + +## Planned Sections + +- Standard mode +- WebSocket mode +- Signing providers +- App connection manager +- Gift/social event handling +- Common failures and escalation +- Historical vs current behavior diff --git a/docs/agents/08-platform-sources/twitch.md b/docs/agents/08-platform-sources/twitch.md new file mode 100644 index 000000000..635fafd79 --- /dev/null +++ b/docs/agents/08-platform-sources/twitch.md @@ -0,0 +1,29 @@ +# Twitch Source + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document Twitch capture, WebSocket/EventSub behavior, OAuth, chat sending, badges/emotes, and known support issues. + +## Source Anchors + +- `social_stream/sources/twitch.js` +- `social_stream/sources/websocket/twitch.html` +- `social_stream/sources/websocket/twitch.js` +- `social_stream/providers/twitch/chatClient.js` +- `ssapp/resources/electron-twitch-handler.js` +- `social_stream/tests/twitch-chatClient-subgift.test.js` + +## Starter Notes + +Twitch has classic source behavior plus newer WebSocket/EventSub paths and provider-core code. Support history mentions sign-in/auth loops on some versions. + +## Planned Sections + +- Standard capture +- WebSocket/EventSub capture +- OAuth +- Send/reply behavior +- Emotes and badges +- Common failures diff --git a/docs/agents/08-platform-sources/youtube.md b/docs/agents/08-platform-sources/youtube.md new file mode 100644 index 000000000..5f7f22a56 --- /dev/null +++ b/docs/agents/08-platform-sources/youtube.md @@ -0,0 +1,33 @@ +# YouTube Source + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document YouTube capture modes, setup, OAuth/API behavior, WebSocket/data API behavior, and support issues. + +## Source Anchors + +- `social_stream/sources/youtube.js` +- `social_stream/sources/youtube_static.js` +- `social_stream/sources/youtube_comments.js` +- `social_stream/sources/websocket/youtube.html` +- `social_stream/sources/websocket/youtube.js` +- `social_stream/providers/youtube/*` +- `ssapp/resources/electron-youtube-handler.js` +- `ssapp/youtube.js` +- `social_stream/docs/youtube-project-setup.html` + +## Starter Notes + +Existing support guidance mentions pop-out chat, YouTube Studio behavior, correct `/watch?v=` URLs, auto-select live chat settings, and YouTube WebSocket/Data API modes. + +## Planned Sections + +- Standard capture +- YouTube Studio capture +- WebSocket/Data API capture +- OAuth and custom credentials +- Reply/send behavior +- Common failures +- App vs extension differences diff --git a/docs/agents/09-api-and-integrations/ai-features.md b/docs/agents/09-api-and-integrations/ai-features.md new file mode 100644 index 000000000..f67f0574d --- /dev/null +++ b/docs/agents/09-api-and-integrations/ai-features.md @@ -0,0 +1,34 @@ +# AI Features + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document SSN AI/cohost/chatbot features and how they connect to live chat. + +## Source Anchors + +- `social_stream/ai.js` +- `social_stream/ai.md` +- `social_stream/aiprompt.html` +- `social_stream/aioverlay.html` +- `social_stream/cohost.html` +- `social_stream/cohost-overlay.html` +- `social_stream/chatbot.html` +- `social_stream/shared/ai/*` +- `social_stream/scripts/playwright-ai*.cjs` +- `social_stream/tests/rag-*.test.js` + +## Starter Notes + +AI features include self-hosted or provider-backed bot behavior, cohost overlays, local browser models, prompt pages, RAG tests, and live chat monitoring/response modes. + +## Planned Sections + +- AI settings +- Provider choices +- Local browser model assets +- Cohost overlay +- Chatbot/live response mode +- Safety and moderation +- Tests and limitations diff --git a/docs/agents/09-api-and-integrations/event-flow-editor.md b/docs/agents/09-api-and-integrations/event-flow-editor.md new file mode 100644 index 000000000..611c8aa4c --- /dev/null +++ b/docs/agents/09-api-and-integrations/event-flow-editor.md @@ -0,0 +1,32 @@ +# Event Flow Editor + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document the Event Flow Editor, triggers, actions, state nodes, tests, and common use cases. + +## Source Anchors + +- `social_stream/actions/EventFlowEditor.js` +- `social_stream/actions/EventFlowSystem.js` +- `social_stream/actions/event-flow-guide.html` +- `social_stream/actions/state-nodes-guide.html` +- `social_stream/actions/STATE_NODES_EXPLANATION.md` +- `social_stream/docs/kick-channel-points-event-flow.md` +- `social_stream/tests/eventflow-*.test.js` + +## Starter Notes + +The Event Flow system is a visual automation layer. It should be documented with exact trigger/action names from source, not guessed UI labels. + +## Planned Sections + +- Editor concepts +- Triggers +- Actions +- State nodes +- Custom JS +- Media and OBS actions +- Kick rewards example +- Testing and troubleshooting diff --git a/docs/agents/09-api-and-integrations/index.md b/docs/agents/09-api-and-integrations/index.md new file mode 100644 index 000000000..d008a820e --- /dev/null +++ b/docs/agents/09-api-and-integrations/index.md @@ -0,0 +1,17 @@ +# API And Integrations Index + +Status: framework only. Detailed extraction not started. + +## Purpose + +This section covers external APIs, automation, OBS, StreamDeck, Companion, Streamer.bot, Event Flow, TTS, and AI integrations. + +## Pages + +- `websocket-http-api.md` +- `obs.md` +- `streamdeck-companion.md` +- `streamerbot.md` +- `event-flow-editor.md` +- `tts.md` +- `ai-features.md` diff --git a/docs/agents/09-api-and-integrations/obs.md b/docs/agents/09-api-and-integrations/obs.md new file mode 100644 index 000000000..21137c8d3 --- /dev/null +++ b/docs/agents/09-api-and-integrations/obs.md @@ -0,0 +1,30 @@ +# OBS Integration + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document using SSN with OBS browser sources, window capture, OBS WebSocket, and common overlay display issues. + +## Source Anchors + +- `social_stream/README.md` +- `social_stream/dock.html` +- `social_stream/featured.html` +- `social_stream/obs-websocket-test.html` +- `social_stream/api.md` +- `stevesbot/resources/learnings/playbooks/playbook-obs-overlay-issues.md` + +## Starter Notes + +OBS is a central workflow. Support issues often involve wrong URLs, missing session IDs, transparent pages appearing white in browsers, browser-source refreshes, and audio/TTS routing. + +## Planned Sections + +- Browser source setup +- Dock vs featured overlay +- Transparent backgrounds +- Recommended sizes +- OBS WebSocket control +- Audio/TTS routing +- Troubleshooting diff --git a/docs/agents/09-api-and-integrations/streamdeck-companion.md b/docs/agents/09-api-and-integrations/streamdeck-companion.md new file mode 100644 index 000000000..2a32eb0d6 --- /dev/null +++ b/docs/agents/09-api-and-integrations/streamdeck-companion.md @@ -0,0 +1,26 @@ +# StreamDeck And Bitfocus Companion + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document StreamDeck and Bitfocus Companion control of SSN through API commands. + +## Source Anchors + +- `social_stream/api.md` +- `social_stream/popup.html` +- `social_stream/background.js` + +## Starter Notes + +Existing API docs include StreamDeck and Companion setup sections. This page should extract command examples, required settings, and troubleshooting. + +## Planned Sections + +- Enable API server +- Choose channel/endpoint +- Common actions +- Variables +- Multi-action examples +- Failure checks diff --git a/docs/agents/09-api-and-integrations/streamerbot.md b/docs/agents/09-api-and-integrations/streamerbot.md new file mode 100644 index 000000000..9cfdd96a6 --- /dev/null +++ b/docs/agents/09-api-and-integrations/streamerbot.md @@ -0,0 +1,26 @@ +# Streamer.bot Integration + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document Streamer.bot integration setup and troubleshooting. + +## Source Anchors + +- `social_stream/streamerbot.html` +- `social_stream/popup.html` +- `social_stream/background.js` +- `social_stream/api.md` + +## Starter Notes + +Popup settings include Streamer.bot WebSocket fields. Existing setup pages should be extracted before giving exact setup instructions. + +## Planned Sections + +- Streamer.bot setup +- Required SSN settings +- Action IDs and WebSocket password +- Event routing +- Troubleshooting diff --git a/docs/agents/09-api-and-integrations/tts.md b/docs/agents/09-api-and-integrations/tts.md new file mode 100644 index 000000000..21605217f --- /dev/null +++ b/docs/agents/09-api-and-integrations/tts.md @@ -0,0 +1,32 @@ +# Text To Speech + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document SSN TTS features, providers, local/browser TTS, cloud TTS, routing, and troubleshooting. + +## Source Anchors + +- `social_stream/tts.html` +- `social_stream/tts.js` +- `social_stream/docs/tts.html` +- `social_stream/docs/local-tts.html` +- `social_stream/local-tts-bridge/*` +- `ssapp/tts-worker.js` +- `ssapp/tests/electron/tts-diagnostics.js` +- `stevesbot/resources/instructions/social-stream-support.md` + +## Starter Notes + +Support guidance mentions system playback device behavior, OBS audio control, cloud API key restrictions, and provider-specific setup. + +## Planned Sections + +- Browser/system TTS +- Cloud providers +- Local TTS bridge +- App TTS worker +- URL parameters and settings +- OBS audio routing +- Common failures diff --git a/docs/agents/09-api-and-integrations/websocket-http-api.md b/docs/agents/09-api-and-integrations/websocket-http-api.md new file mode 100644 index 000000000..3e528cd99 --- /dev/null +++ b/docs/agents/09-api-and-integrations/websocket-http-api.md @@ -0,0 +1,30 @@ +# WebSocket And HTTP API + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document SSN external control and message APIs. + +## Source Anchors + +- `social_stream/api.md` +- `social_stream/background.js` +- `social_stream/dock.html` +- `social_stream/simple_api_client.html` +- `social_stream/sampleapi.html` +- `social_stream/tests/sse.html` + +## Starter Notes + +Existing `api.md` covers WebSocket API, HTTP API, channels, responses, and special page controls. This page should turn that into agent-friendly, source-checked reference material. + +## Planned Sections + +- API server setup +- WebSocket channels +- HTTP endpoints +- SSE +- Sending commands +- Receiving chat +- Common mistakes diff --git a/docs/agents/10-troubleshooting/auth-and-sign-in.md b/docs/agents/10-troubleshooting/auth-and-sign-in.md new file mode 100644 index 000000000..f5d0c8805 --- /dev/null +++ b/docs/agents/10-troubleshooting/auth-and-sign-in.md @@ -0,0 +1,27 @@ +# Auth And Sign-In + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document platform sign-in, OAuth, cookie/session, and embedded-browser restrictions. + +## Source Anchors + +- `ssapp/resources/electron-*-handler.js` +- `social_stream/sources/websocket/*.html` +- `social_stream/sources/websocket/*.js` +- `stevesbot/resources/instructions/social-stream-support.md` + +## Starter Notes + +Support history mentions Google, Twitch, Kick, LinkedIn, TikTok, and app embedded-browser sign-in blocks. Exact advice should be platform-specific and source-checked. + +## Planned Sections + +- Browser extension auth +- Standalone app auth +- OAuth helpers +- Cookie/session persistence +- Platform-specific auth notes +- Common loops and blocks diff --git a/docs/agents/10-troubleshooting/desktop-app-issues.md b/docs/agents/10-troubleshooting/desktop-app-issues.md new file mode 100644 index 000000000..54fdc43d2 --- /dev/null +++ b/docs/agents/10-troubleshooting/desktop-app-issues.md @@ -0,0 +1,29 @@ +# Desktop App Issues + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document common standalone app issues and differences from the Chrome extension. + +## Source Anchors + +- `ssapp/main.js` +- `ssapp/preload.js` +- `ssapp/state.js` +- `ssapp/README.md` +- `ssapp/tests/electron/*` +- `stevesbot/resources/instructions/social-stream-support.md` + +## Starter Notes + +The app can hit embedded browser login restrictions, settings/persistence issues, source loading issues, and platform-specific differences. It uses the `social_stream` repo as source of truth for loaded Social Stream files. + +## Planned Sections + +- Source window issues +- Embedded auth blocks +- App state/persistence +- Source file resolution +- App update/build confusion +- When to recommend Chrome extension instead diff --git a/docs/agents/10-troubleshooting/extension-not-capturing.md b/docs/agents/10-troubleshooting/extension-not-capturing.md new file mode 100644 index 000000000..892653a3f --- /dev/null +++ b/docs/agents/10-troubleshooting/extension-not-capturing.md @@ -0,0 +1,29 @@ +# Extension Not Capturing + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document what to check when the Chrome extension is installed but messages do not appear. + +## Source Anchors + +- `social_stream/manifest.json` +- `social_stream/service_worker.js` +- `social_stream/background.js` +- `social_stream/popup.html` +- `social_stream/sources/*.js` +- `stevesbot/resources/instructions/social-stream-support.md` + +## Starter Notes + +Support guidance says to check whether the extension icon is enabled, whether chat is popped out, whether the session ID matches, and whether other extensions or browser state are interfering. + +## Planned Sections + +- Enabled/disabled extension state +- Source page loaded +- Pop-out chat requirements +- Session mismatch +- Browser restrictions +- Platform-specific capture problems diff --git a/docs/agents/10-troubleshooting/index.md b/docs/agents/10-troubleshooting/index.md new file mode 100644 index 000000000..21376d5e6 --- /dev/null +++ b/docs/agents/10-troubleshooting/index.md @@ -0,0 +1,17 @@ +# Troubleshooting Index + +Status: framework only. Detailed extraction not started. + +## Purpose + +This section converts code, docs, tests, and support history into practical troubleshooting pages. + +## Pages + +- `quick-triage.md` +- `extension-not-capturing.md` +- `desktop-app-issues.md` +- `auth-and-sign-in.md` +- `obs-overlay-display.md` +- `settings-loss-and-backups.md` +- `platform-known-issues.md` diff --git a/docs/agents/10-troubleshooting/obs-overlay-display.md b/docs/agents/10-troubleshooting/obs-overlay-display.md new file mode 100644 index 000000000..21228dcd8 --- /dev/null +++ b/docs/agents/10-troubleshooting/obs-overlay-display.md @@ -0,0 +1,28 @@ +# OBS Overlay Display Issues + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document blank, white, transparent, stale, hidden, incorrectly styled, or non-updating overlays in OBS/browser. + +## Source Anchors + +- `social_stream/dock.html` +- `social_stream/featured.html` +- `social_stream/docs/customoverlays.md` +- `social_stream/parameters.md` +- `stevesbot/resources/learnings/playbooks/playbook-obs-overlay-issues.md` + +## Starter Notes + +Common causes include missing session ID, using the wrong page, transparent backgrounds, stale OBS browser source cache, CSS hiding text, and unmatched dock/overlay sessions. + +## Planned Sections + +- Dock vs featured confusion +- Missing or wrong session +- Transparent output +- White text/background styling +- Refresh/cache issues +- Browser source permissions diff --git a/docs/agents/10-troubleshooting/platform-known-issues.md b/docs/agents/10-troubleshooting/platform-known-issues.md new file mode 100644 index 000000000..b1b8307ec --- /dev/null +++ b/docs/agents/10-troubleshooting/platform-known-issues.md @@ -0,0 +1,29 @@ +# Platform Known Issues + +Status: framework only. Detailed extraction not started. + +## Purpose + +Track platform-specific known issues from code and support history. + +## Source Anchors + +- `stevesbot/resources/learnings/social-stream-ninja-top-issues.md` +- `stevesbot/data/sqlite/knowledge.sqlite` +- `social_stream/sources/*` +- `ssapp/tests/tiktok/*` + +## Starter Notes + +High-volume support areas include TikTok, YouTube, Kick, Twitch, Rumble, Facebook, and OBS display problems. Mark support-derived claims as historical until source-checked. + +## Planned Sections + +- TikTok +- YouTube +- Kick +- Twitch +- Rumble +- Facebook +- Other platforms +- Historical/stale claims diff --git a/docs/agents/10-troubleshooting/quick-triage.md b/docs/agents/10-troubleshooting/quick-triage.md new file mode 100644 index 000000000..9ecc8be41 --- /dev/null +++ b/docs/agents/10-troubleshooting/quick-triage.md @@ -0,0 +1,126 @@ +# Quick Triage + +Status: backbone extraction pass. Usable for first-pass support, not final-grade. + +## Purpose + +Give agents a short first-pass troubleshooting checklist for common SSN support questions. + +## Source Anchors + +- `stevesbot/resources/instructions/social-stream-support.md` +- `stevesbot/resources/learnings/social-stream-ninja-top-issues.md` +- `social_stream/docs/support.html` +- `social_stream/README.md` +- `social_stream/about.md` +- `social_stream/manifest.json` +- `ssapp/README.md` + +## First 60-Second Checks + +Start with these before platform-specific advice: + +- Confirm whether the user is using the Chrome extension, the standalone Electron app, Electron Capture, or a hosted overlay page. +- Confirm the source page and dock/overlay/API client use the same session ID. +- Confirm the extension/app is enabled and the extension icon/state is on. +- Ask whether the chat/source is popped out when the platform requires a popout. +- Ask whether refreshing the source page and refreshing the OBS browser source changes anything. +- Confirm they are not using an old dock/overlay URL from a previous session. +- Confirm whether the problem is capture, routing, display, or control: + - capture: SSN does not see messages + - routing: dock sees messages but overlay/API does not + - display: overlay loads but text/media is invisible or misplaced + - control: messages arrive but send/delete/block/feature actions fail +- Ask for the exact platform, source URL, dock/overlay URL type, app/extension version, and whether this worked before. + +## Required Info To Ask For + +Ask for: + +- Product surface: Chrome extension or standalone app. +- Platform/source: YouTube, TikTok, Twitch, Kick, Facebook, Instagram, Rumble, Discord, generic/custom, or other. +- Capture mode when relevant: normal DOM capture, WebSocket mode, API mode, or app-specific connector. +- Whether the source is live right now. +- Exact symptom: no messages, delayed messages, duplicates, missing events, overlay blank, OBS only, auth blocked, settings lost, or control action failed. +- Whether dock receives messages. +- Whether browser preview receives messages outside OBS. +- Whether the same session ID appears on both sender and receiver. + +Do not ask for private credentials or tokens. If logs are needed, ask for redacted logs/screenshots. + +## Quick Branches + +### Extension not capturing + +Use this branch when no messages reach the dock: + +- Verify the extension is enabled/on. +- Reload the platform page after enabling. +- Use popout chat when the platform requires it. +- Check for wrong platform URL, old stream URL, or non-live stream. +- Try a clean Chrome profile/incognito only when needed to isolate conflicting extensions or cookies. +- Check whether the platform has a WebSocket connector and whether that mode is more appropriate. + +### Dock receives messages, overlay does not + +Use this branch when capture works but display does not: + +- Verify dock and overlay have the same session ID. +- Refresh the OBS browser source or browser tab running the overlay. +- Check URL parameters that hide text, hide events, filter events, or change display style. +- Test the overlay in a normal browser outside OBS. +- For transparent overlays, remember that white/blank-looking pages can be expected in a browser preview if the visible text is white on transparent/white background. + +### Standalone app issue + +Use this branch when the user is in the Electron app: + +- Confirm the app is using the intended Social Stream source root, not an invalid folder or stale imported zip. +- If login is blocked inside the app, try the Chrome extension path or a WebSocket connector from the regular browser where possible. +- For settings loss, avoid telling the user to clear app data first. Preserve settings/backups and inspect app storage behavior. +- If a workflow works in Chrome but not in the app, suspect Electron login context, preload bridge, IPC, or app-specific platform handler differences. + +### OBS/browser source issue + +Use this branch when it works in a normal browser but not OBS: + +- Refresh the OBS browser source. +- Verify the OBS URL is the current overlay URL. +- Check browser-source dimensions. +- Disable or revise custom CSS temporarily. +- Confirm the overlay is not intentionally transparent, hidden, filtered, or waiting for a featured message/event. + +## Platform Short Notes + +These are support-history notes and should be source-checked during platform deep dives: + +- YouTube: popout chat or supported Studio flow may matter. WebSocket mode can cover events that DOM mode does not. +- TikTok: fragile and frequently affected by platform changes. Username should usually be entered without `@`, and the account must be live. WebSocket/API modes and app signing behavior need exact docs. +- Kick: popout/sign-in/captcha state can block capture. Chrome extension or WebSocket mode may be more reliable than embedded app sign-in for some users. +- Twitch: distinguish normal chat capture from EventSub/WebSocket event features. +- Rumble/Facebook/Instagram/Discord: verify exact source URL format and whether the source is supported in extension, app, or both. + +## When To Recommend Updating + +Recommend updating when: + +- The issue matches a known platform breakage category. +- The user's version is old compared with current repo/release notes. +- A platform connector depends on a recent manifest/source-script/provider change. + +Avoid saying "update" as the only answer. Pair it with one concrete verification step and one fallback path. + +## When To Escalate + +Escalate or mark for deeper investigation when: + +- Multiple users report the same platform failure after normal checks. +- The platform page layout/API changed. +- Dock receives malformed data. +- WebSocket/API actions fail while display-only flow works. +- The standalone app loses settings repeatedly after current repair logic should preserve them. +- Auth failures involve provider policy changes or embedded-browser restrictions. + +## Extraction Notes + +Deeper troubleshooting pages should split by symptom and platform. This page is only the first-pass routing checklist. diff --git a/docs/agents/10-troubleshooting/settings-loss-and-backups.md b/docs/agents/10-troubleshooting/settings-loss-and-backups.md new file mode 100644 index 000000000..7f3d0155b --- /dev/null +++ b/docs/agents/10-troubleshooting/settings-loss-and-backups.md @@ -0,0 +1,30 @@ +# Settings Loss And Backups + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document settings loss, export/import, backup/restore, and app/extension storage differences. + +## Source Anchors + +- `ssapp/state.js` +- `ssapp/settings-backup.js` +- `ssapp/transfer-backup.js` +- `ssapp/transfer-restore-runner.js` +- `ssapp/tests/electron/settings-*.js` +- `social_stream/popup.js` +- `stevesbot/resources/instructions/social-stream-support.md` + +## Starter Notes + +Support guidance says standalone app settings loss is recurring and can be caused by cleanup tools, AV, updates, or storage cleanup. Extension uninstalling can also delete settings. + +## Planned Sections + +- Where settings live +- Export/import guidance +- App backup/restore +- Extension update without uninstalling +- Known failure causes +- Recovery steps diff --git a/docs/agents/11-support-kb/common-questions.md b/docs/agents/11-support-kb/common-questions.md new file mode 100644 index 000000000..2dda48ac7 --- /dev/null +++ b/docs/agents/11-support-kb/common-questions.md @@ -0,0 +1,31 @@ +# Common Support Questions + +Status: framework only. Detailed extraction not started. + +## Purpose + +Collect common SSN support questions and source-backed answers. + +## Source Anchors + +- `stevesbot/resources/learnings/social-stream-ninja-top-issues.md` +- `stevesbot/resources/learnings/support-qa/social-stream-qa.md` +- `stevesbot/resources/learnings/support-qa/social-stream-qa-expanded.md` +- `stevesbot/data/sqlite/stevesbot.sqlite` +- `stevesbot/data/sqlite/knowledge.sqlite` + +## Starter Notes + +This should become a practical agent FAQ, but every answer should be checked against current code/docs before being treated as current. + +## Planned Sections + +- Capture not working +- Overlay not updating +- Auth/sign-in +- TikTok +- YouTube +- Kick +- TTS +- Settings loss +- Customization diff --git a/docs/agents/11-support-kb/historical-issues.md b/docs/agents/11-support-kb/historical-issues.md new file mode 100644 index 000000000..188769c5a --- /dev/null +++ b/docs/agents/11-support-kb/historical-issues.md @@ -0,0 +1,25 @@ +# Historical Support Issues + +Status: framework only. Detailed extraction not started. + +## Purpose + +Track issues seen in support history that may no longer apply, or that need current-source verification. + +## Source Anchors + +- `stevesbot/resources/learnings/social-stream-ninja-top-issues.md` +- `stevesbot/data/sqlite/knowledge.sqlite` +- `stevesbot/data/sqlite/archive.sqlite` + +## Starter Notes + +Platform behavior changes frequently. A support answer that was right for an older SSN version or platform API may be wrong now. + +## Planned Sections + +- Version-specific issues +- Platform-side breakages +- Fixed bugs +- Stale setup instructions +- Claims needing source verification diff --git a/docs/agents/11-support-kb/mining-method.md b/docs/agents/11-support-kb/mining-method.md new file mode 100644 index 000000000..9ef0cde54 --- /dev/null +++ b/docs/agents/11-support-kb/mining-method.md @@ -0,0 +1,27 @@ +# Support KB Mining Method + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document how to mine `stevesbot` support data safely and usefully for SSN docs. + +## Source Anchors + +- `stevesbot/resources/instructions/social-stream-support.md` +- `stevesbot/resources/learnings/**` +- `stevesbot/data/sqlite/*.sqlite` +- `stevesbot/data/mined-threads/*.jsonl` + +## Starter Notes + +Prefer curated and summarized data before raw Discord archive data. Treat support material as evidence and current code as source of truth. + +## Planned Sections + +- Safe source order +- SQLite query units +- Filtering SSN from unrelated products +- Anonymization rules +- Historical claim handling +- Pass logging diff --git a/docs/agents/11-support-kb/support-source-map.md b/docs/agents/11-support-kb/support-source-map.md new file mode 100644 index 000000000..9719274b5 --- /dev/null +++ b/docs/agents/11-support-kb/support-source-map.md @@ -0,0 +1,28 @@ +# Support Source Map + +Status: framework only. Detailed extraction not started. + +## Purpose + +Map each `stevesbot` support source to the kind of SSN documentation it can inform. + +## Source Anchors + +- `stevesbot/resources/instructions/social-stream-support.md` +- `stevesbot/resources/learnings/social-stream-ninja-top-issues.md` +- `stevesbot/resources/learnings/support-qa/social-stream-*.md` +- `stevesbot/resources/learnings/playbooks/*` +- `stevesbot/data/sqlite/*.sqlite` + +## Starter Notes + +The useful support sources are mixed with unrelated product material. This page should keep the SSN-relevant support map explicit. + +## Planned Sections + +- Curated support instructions +- Generated issue summaries +- Q&A exports +- Playbooks +- SQLite tables +- Raw transcript/archive usage diff --git a/docs/agents/11-support-kb/unresolved-or-stale-claims.md b/docs/agents/11-support-kb/unresolved-or-stale-claims.md new file mode 100644 index 000000000..d7879549f --- /dev/null +++ b/docs/agents/11-support-kb/unresolved-or-stale-claims.md @@ -0,0 +1,26 @@ +# Unresolved Or Stale Claims + +Status: framework only. Detailed extraction not started. + +## Purpose + +Track claims that should not be promoted into final docs until verified. + +## Source Anchors + +- `stevesbot/resources/learnings/unresolved-analysis.md` +- `stevesbot/resources/learnings/social-stream-ninja-top-issues.md` +- `stevesbot/data/sqlite/knowledge.sqlite` +- Current SSN source files + +## Starter Notes + +Use this as a holding area for contradictions, old support advice, or claims that require line-level source review. + +## Planned Sections + +- Claim +- Source +- Risk +- Verification needed +- Final decision diff --git a/docs/agents/12-development/adding-a-source.md b/docs/agents/12-development/adding-a-source.md new file mode 100644 index 000000000..fdd8221b6 --- /dev/null +++ b/docs/agents/12-development/adding-a-source.md @@ -0,0 +1,30 @@ +# Adding A Source + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document how to add or modify a platform source safely. + +## Source Anchors + +- `social_stream/sources/README.md` +- `social_stream/sources/*.js` +- `social_stream/manifest.json` +- `social_stream/background.js` +- `social_stream/docs/event-reference.html` +- `ssapp/tests/electron/source-url-parsing-regression.js` + +## Starter Notes + +Source scripts may run in both the extension and the app. They need compatibility with old-school browser scripts and should preserve event payload contracts. + +## Planned Sections + +- Source file pattern +- Manifest changes +- Icons and settings +- WebSocket source pattern +- Payload fields +- App compatibility +- Tests and docs updates diff --git a/docs/agents/12-development/build-and-release-boundaries.md b/docs/agents/12-development/build-and-release-boundaries.md new file mode 100644 index 000000000..4f6d7a4a5 --- /dev/null +++ b/docs/agents/12-development/build-and-release-boundaries.md @@ -0,0 +1,28 @@ +# Build And Release Boundaries + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document build, packaging, release, and repo-boundary rules relevant to SSN docs. + +## Source Anchors + +- `ssapp/RELEASE.md` +- `ssapp/package.json` +- `ssapp/scripts/*` +- `social_stream/README.md` +- `social_stream/docs/download.html` + +## Starter Notes + +App release tags and artifacts belong in `steveseguin/social_stream`, not in `ssapp`. This page should be source-checked before any release/deploy work. + +## Planned Sections + +- Extension release surfaces +- Standalone app builds +- Fallback bundle warning +- Release note style +- Artifact upload boundaries +- Do-not-do list diff --git a/docs/agents/12-development/repo-map.md b/docs/agents/12-development/repo-map.md new file mode 100644 index 000000000..e698b8758 --- /dev/null +++ b/docs/agents/12-development/repo-map.md @@ -0,0 +1,29 @@ +# Development Repo Map + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document where code lives and which repo/file should be changed for SSN development work. + +## Source Anchors + +- `social_stream/AGENTS.md` +- `ssapp/AGENTS.md` +- `social_stream/manifest.json` +- `ssapp/package.json` +- `ssapp/resources/README.md` + +## Starter Notes + +`social_stream` is the source of truth for Social Stream source files. `ssapp` loads those files and should not treat its fallback bundle as primary source. + +## Planned Sections + +- Repo roles +- Extension files +- App files +- Shared files +- Public docs +- Tests +- Files to avoid diff --git a/docs/agents/12-development/shared-code-rules.md b/docs/agents/12-development/shared-code-rules.md new file mode 100644 index 000000000..222ebeb31 --- /dev/null +++ b/docs/agents/12-development/shared-code-rules.md @@ -0,0 +1,28 @@ +# Shared Code Rules + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document rules for code shared between extension, app, hosted pages, and standalone web surfaces. + +## Source Anchors + +- `social_stream/AGENTS.md` +- `social_stream/shared/**` +- `social_stream/providers/**` +- `social_stream/sources/websocket/**` +- `ssapp/preload.js` + +## Starter Notes + +Repo instructions say shared source scripts must work in both Chrome extension and Electron app contexts. Provider cores should remain environment agnostic. + +## Planned Sections + +- Chrome 80 compatibility +- No remote executable code in extension package +- Dynamic import patterns +- Provider core boundaries +- Shared utility placement +- Manifest/web-accessible resources diff --git a/docs/agents/12-development/testing-and-validation.md b/docs/agents/12-development/testing-and-validation.md new file mode 100644 index 000000000..d251323ed --- /dev/null +++ b/docs/agents/12-development/testing-and-validation.md @@ -0,0 +1,28 @@ +# Testing And Validation + +Status: framework only. Detailed extraction not started. + +## Purpose + +Document tests, diagnostics, and what counts as validation for SSN docs and development. + +## Source Anchors + +- `social_stream/tests/*` +- `social_stream/scripts/playwright-*.cjs` +- `ssapp/tests/electron/*` +- `ssapp/tests/tiktok/*` +- `ssapp/AGENTS.md` + +## Starter Notes + +The app repo instructions say smoke/unit checks are not considered full testing for Electron/app changes. Actual testing means functional in-app/end-to-end validation of real workflows. + +## Planned Sections + +- Extension tests +- Playwright scripts +- App diagnostics +- TikTok tests +- Manual app testing +- Documentation verification checklist diff --git a/docs/agents/99-agent-index.md b/docs/agents/99-agent-index.md new file mode 100644 index 000000000..116e3ce77 --- /dev/null +++ b/docs/agents/99-agent-index.md @@ -0,0 +1,40 @@ +# SSN AI Documentation Index + +Status: framework plus first source-backed backbone pass. + +## Start Here + +- `AGENT.md`: scope, write boundary, source priority, and exclusions. +- `00-inventory-and-plan.md`: initial inventory and proposed structure. +- `01-extraction-checklist.md`: pass tracking, extraction levels, and status labels. +- `02-resource-manifest.md`: resource inventory for code, docs, and support data. + +## Core Topic Pages + +- `01-product-map.md`: framework only. +- `02-installation-and-surfaces.md`: framework only. +- `03-extension-architecture.md`: backbone extraction pass complete. +- `04-standalone-app-architecture.md`: backbone extraction pass complete. +- `05-message-flow-and-event-contracts.md`: backbone extraction pass complete. +- `06-settings-sessions-and-storage.md`: backbone extraction pass complete. + +## Sections + +- `07-overlays-and-pages/index.md` +- `08-platform-sources/index.md` +- `09-api-and-integrations/index.md` +- `10-troubleshooting/index.md` +- `11-support-kb/mining-method.md` +- `12-development/repo-map.md` + +## Suggested Next Pass + +Run a heavy extraction pass on one of these areas: + +1. `08-platform-sources/youtube.md`, `tiktok.md`, `twitch.md`, and `kick.md` +2. `09-api-and-integrations/websocket-http-api.md` plus `social_stream/api.md` +3. `07-overlays-and-pages/dock.md` and `featured.md` +4. `10-troubleshooting/extension-not-capturing.md`, `desktop-app-issues.md`, and `settings-loss-and-backups.md` +5. File-level support mining in `11-support-kb/*` + +The backbone pages now identify the main architecture and storage boundaries. The next passes should fill in exact setup steps, source files processed, platform differences, and support-confirmed failure modes. diff --git a/docs/agents/AGENT.md b/docs/agents/AGENT.md new file mode 100644 index 000000000..55016ed62 --- /dev/null +++ b/docs/agents/AGENT.md @@ -0,0 +1,78 @@ +# SSN AI Documentation Agent Brief + +This folder is a temporary, AI-focused documentation workspace for Social Stream Ninja. It is not a release artifact, not a ZIP package, and should not be treated as end-user website docs unless Steve later asks for that. + +## Scope + +Create exhaustive markdown documentation for: + +- Social Stream Ninja Chrome extension in `C:\Users\steve\Code\social_stream` +- Social Stream Ninja standalone Electron app in `C:\Users\steve\Code\ssapp` +- Shared behavior between the extension and app, especially source scripts, overlays, sessions, APIs, settings, and troubleshooting +- Support knowledge from `C:\Users\steve\Code\stevesbot`, filtered to SSN-related material + +## Write Boundary + +Only write inside: + +`C:\Users\steve\Code\social_stream\docs\agents` + +Do not edit project code, public docs, generated docs, release files, app files, or support bot files while building this documentation set unless Steve explicitly changes the scope. + +## Source Priority + +Use sources in this order: + +1. Current code in `social_stream` and `ssapp` +2. Existing repo docs in `social_stream`, especially `README.md`, `api.md`, `parameters.md`, `docs/event-reference.html`, `docs/customoverlays.md`, `docs/ssapp.html`, `docs/tiktok-guide.html`, `docs/local-tts.html`, and `docs/tts.html` +3. Current app docs in `ssapp`, especially `README.md`, `RELEASE.md`, and test files that document expected behavior +4. Curated support material in `stevesbot/resources/instructions` and `stevesbot/resources/learnings` +5. SQLite summaries in `stevesbot/resources/knowledge.sqlite`, `stevesbot/data/sqlite/knowledge.sqlite`, and `stevesbot/data/sqlite/stevesbot.sqlite` +6. Raw Discord archive data only when needed to confirm real-world symptoms, wording, or frequency + +## Exclusions + +Do not use or document from: + +- `C:\Users\steve\Code\ssapp\resources\social_stream_fallback` +- `C:\Users\steve\Code\stevesbot\resources\secrets` +- Non-SSN support content unless it directly clarifies an SSN integration +- Raw private support identities unless they are needed as anonymized examples + +## Documentation Style + +Write for future AI agents first, but keep the content usable by humans. Prefer factual, source-backed notes over generic guidance. + +Each topic page should include: + +- Purpose +- Where the relevant code and docs live +- How the feature works +- How users set it up +- Common failure modes +- Troubleshooting steps +- Known differences between Chrome extension and standalone app +- Open questions or areas needing deeper review + +When support data conflicts with current code, mark it as historical and verify against source before turning it into current guidance. + +## Current First Pass + +The starting inventory and proposed file structure are in: + +`docs/agents/00-inventory-and-plan.md` + +Use these before starting any extraction pass: + +- `docs/agents/01-extraction-checklist.md` +- `docs/agents/02-resource-manifest.md` + +The first source-backed backbone pages are: + +- `docs/agents/03-extension-architecture.md` +- `docs/agents/04-standalone-app-architecture.md` +- `docs/agents/05-message-flow-and-event-contracts.md` +- `docs/agents/06-settings-sessions-and-storage.md` +- `docs/agents/10-troubleshooting/quick-triage.md` + +These are orientation-grade, not final. Treat them as the base map for deeper platform, API, settings, and support-KB extraction. diff --git a/docs/agents/_templates/extraction-pass.md b/docs/agents/_templates/extraction-pass.md new file mode 100644 index 000000000..c056fa353 --- /dev/null +++ b/docs/agents/_templates/extraction-pass.md @@ -0,0 +1,27 @@ +# Extraction Pass Template + +## Pass Metadata + +- Date: +- Agent: +- Scope: +- Level: quick | heavy | intense +- Output docs: + +## Sources Processed + +| Source | Type | Level | Notes | +| --- | --- | --- | --- | +| | | | | + +## Facts Added + +- + +## Claims Rejected Or Marked Historical + +- + +## Follow-Up Needed + +- diff --git a/docs/agents/_templates/topic-page.md b/docs/agents/_templates/topic-page.md new file mode 100644 index 000000000..9fe06bb14 --- /dev/null +++ b/docs/agents/_templates/topic-page.md @@ -0,0 +1,38 @@ +# Topic Page Template + +Status: template + +## Purpose + +Describe what this topic covers and what kind of user or agent question it should answer. + +## Source Anchors + +- Current code: +- Existing docs: +- Support data: +- Tests or validation: + +## Current Understanding + +Write source-backed facts here. Separate confirmed facts from assumptions. + +## How It Works + +Describe runtime flow, setup flow, configuration, and app/extension differences. + +## User Setup + +List the practical setup steps a user should follow. + +## Common Failures + +List symptoms, likely causes, and first checks. + +## Extraction Notes + +Track which source files were processed and at what level. + +## Open Questions + +Keep unknowns visible until confirmed. From 6a900a281989c8317dcebe512144dd6cb53c332f Mon Sep 17 00:00:00 2001 From: steveseguin Date: Tue, 23 Jun 2026 22:26:14 -0400 Subject: [PATCH 18/30] docs(agents): add reference section and update extraction progress - Added `13-reference/` index and cross-cutting lookup pages for commands, URL parameters, modes, free/paid boundaries, plugins/customization, support resources, and features/capabilities. - Updated extraction checklist (`01-extraction-checklist.md`) to mark numerous heavy passes as complete (source inventory, platform sources, product map, support KB mining, etc.). - Refined inventory plan (`00-inventory-and-plan.md`) with new page roles and updated open questions. [auto-enhanced] --- docs/agents/00-inventory-and-plan.md | 19 +- docs/agents/01-extraction-checklist.md | 99 ++-- docs/agents/01-product-map.md | 157 +++++- docs/agents/02-installation-and-surfaces.md | 234 ++++++++- .../07-overlays-and-pages/custom-overlays.md | 261 +++++++++- docs/agents/07-overlays-and-pages/dock.md | 216 ++++++++- docs/agents/07-overlays-and-pages/featured.md | 239 ++++++++- docs/agents/07-overlays-and-pages/index.md | 19 +- .../07-overlays-and-pages/multi-alerts.md | 236 ++++++++- .../waitlist-polls-games.md | 364 +++++++++++++- docs/agents/08-platform-sources/discord.md | 132 ++++- docs/agents/08-platform-sources/facebook.md | 180 ++++++- .../generic-and-custom-sources.md | 237 ++++++++- docs/agents/08-platform-sources/index.md | 34 +- docs/agents/08-platform-sources/instagram.md | 136 +++++- docs/agents/08-platform-sources/kick.md | 169 ++++++- .../manifest-content-scripts.md | 171 +++++++ docs/agents/08-platform-sources/rumble.md | 186 ++++++- .../08-platform-sources/source-inventory.md | 459 ++++++++++++++++++ docs/agents/08-platform-sources/tiktok.md | 147 +++++- docs/agents/08-platform-sources/twitch.md | 157 +++++- docs/agents/08-platform-sources/youtube.md | 136 +++++- .../09-api-and-integrations/ai-features.md | 236 +++++++-- .../event-flow-editor.md | 374 +++++++++++++- docs/agents/09-api-and-integrations/index.md | 24 +- docs/agents/09-api-and-integrations/obs.md | 172 ++++++- .../streamdeck-companion.md | 199 +++++++- .../09-api-and-integrations/streamerbot.md | 188 ++++++- docs/agents/09-api-and-integrations/tts.md | 255 +++++++++- .../websocket-http-api.md | 373 +++++++++++++- .../10-troubleshooting/auth-and-sign-in.md | 217 ++++++++- .../10-troubleshooting/desktop-app-issues.md | 160 +++++- .../extension-not-capturing.md | 164 ++++++- docs/agents/10-troubleshooting/index.md | 24 +- .../10-troubleshooting/obs-overlay-display.md | 187 ++++++- .../platform-known-issues.md | 90 +++- .../settings-loss-and-backups.md | 212 +++++++- docs/agents/11-support-kb/common-questions.md | 383 ++++++++++++++- .../agents/11-support-kb/historical-issues.md | 311 +++++++++++- docs/agents/11-support-kb/mining-method.md | 209 +++++++- .../11-support-kb/support-source-map.md | 51 +- .../unresolved-or-stale-claims.md | 72 ++- docs/agents/12-development/adding-a-source.md | 262 +++++++++- .../build-and-release-boundaries.md | 169 ++++++- docs/agents/12-development/index.md | 33 ++ .../provider-cores-and-shared-utils.md | 130 +++++ docs/agents/12-development/repo-map.md | 152 +++++- .../12-development/shared-code-rules.md | 193 +++++++- .../12-development/testing-and-validation.md | 195 +++++++- .../13-reference/commands-and-actions.md | 230 +++++++++ .../custom-plugins-and-extensions.md | 283 +++++++++++ .../13-reference/features-and-capabilities.md | 182 +++++++ .../free-paid-and-support-boundaries.md | 145 ++++++ docs/agents/13-reference/index.md | 50 ++ .../modes-and-capability-matrix.md | 103 ++++ .../13-reference/settings-and-toggles.md | 198 ++++++++ .../support-resources-and-escalation.md | 134 +++++ docs/agents/13-reference/url-parameters.md | 227 +++++++++ docs/agents/99-agent-index.md | 42 +- docs/event-reference.html | 2 +- sources/youtube.js | 78 ++- 61 files changed, 10019 insertions(+), 678 deletions(-) create mode 100644 docs/agents/08-platform-sources/manifest-content-scripts.md create mode 100644 docs/agents/08-platform-sources/source-inventory.md create mode 100644 docs/agents/12-development/index.md create mode 100644 docs/agents/12-development/provider-cores-and-shared-utils.md create mode 100644 docs/agents/13-reference/commands-and-actions.md create mode 100644 docs/agents/13-reference/custom-plugins-and-extensions.md create mode 100644 docs/agents/13-reference/features-and-capabilities.md create mode 100644 docs/agents/13-reference/free-paid-and-support-boundaries.md create mode 100644 docs/agents/13-reference/index.md create mode 100644 docs/agents/13-reference/modes-and-capability-matrix.md create mode 100644 docs/agents/13-reference/settings-and-toggles.md create mode 100644 docs/agents/13-reference/support-resources-and-escalation.md create mode 100644 docs/agents/13-reference/url-parameters.md diff --git a/docs/agents/00-inventory-and-plan.md b/docs/agents/00-inventory-and-plan.md index 32e7972c5..c968cbe72 100644 --- a/docs/agents/00-inventory-and-plan.md +++ b/docs/agents/00-inventory-and-plan.md @@ -186,6 +186,8 @@ docs/agents/ rumble.md discord.md generic-and-custom-sources.md + source-inventory.md + manifest-content-scripts.md 09-api-and-integrations/ websocket-http-api.md obs.md @@ -212,8 +214,19 @@ docs/agents/ repo-map.md adding-a-source.md shared-code-rules.md + provider-cores-and-shared-utils.md testing-and-validation.md build-and-release-boundaries.md + 13-reference/ + index.md + commands-and-actions.md + url-parameters.md + modes-and-capability-matrix.md + free-paid-and-support-boundaries.md + custom-plugins-and-extensions.md + support-resources-and-escalation.md + settings-and-toggles.md + features-and-capabilities.md 99-agent-index.md ``` @@ -267,6 +280,10 @@ Document how the support data was mined, which sources are trusted, how claims a Document how to safely change SSN: repo map, adding new platform sources, shared-code compatibility rules, tests that matter, Electron differences, build commands, release boundaries, and event-reference update rules. +### `13-reference/*` + +Provide fast cross-cutting lookup pages for commands, URL parameters, product/capture modes, free-vs-paid boundaries, plugin/customization paths, support-resource routing, settings/toggle lookup, and broad feature/capability routing. + ### `99-agent-index.md` Final navigation index for AI agents. This should be generated last, after the detailed pages exist. @@ -297,6 +314,6 @@ For each page: ## First-Pass Open Questions - Which support categories in `stevesbot` should be considered in scope beyond SSN Desktop App, Electron Capture, Caption.Ninja, and OBS overlays? -- Should this documentation include exact UI labels from `popup.html`, or summarize behavior and reference source locations? +- Which exact UI labels from `popup.html` need line-level docs beyond the generated public settings reference? - Should raw support examples be anonymized into scenario pages, or only used to rank common problems? - Should generated agent docs eventually be moved into public docs, or remain temporary/private under `docs/agents`? diff --git a/docs/agents/01-extraction-checklist.md b/docs/agents/01-extraction-checklist.md index d77fabf75..9db4cfd96 100644 --- a/docs/agents/01-extraction-checklist.md +++ b/docs/agents/01-extraction-checklist.md @@ -73,17 +73,31 @@ Add one entry per extraction pass. | 2026-06-23 | Codex | Initial repo/support inventory | Quick | `00-inventory-and-plan.md`, `01-extraction-checklist.md`, `02-resource-manifest.md` | quick-complete | Created tracker and manifest. No detailed extraction yet. | | 2026-06-23 | Codex | Documentation framework and starter pages | Quick | Topic files under `01-*` through `12-*`, `_templates/`, `99-agent-index.md` | quick-complete | Created starter files and section scaffolds. Detailed extraction still not started. | | 2026-06-24 | Codex | Backbone architecture, flow, storage, and triage notes | Heavy | `03-extension-architecture.md`, `04-standalone-app-architecture.md`, `05-message-flow-and-event-contracts.md`, `06-settings-sessions-and-storage.md`, `10-troubleshooting/quick-triage.md`, `AGENT.md`, `99-agent-index.md` | heavy-complete | First source-backed pass using manifest, service worker, background, app preload/state/main notes, and support history. Needs field-level/intense passes later. | +| 2026-06-24 | Codex | Priority platform sources: YouTube, TikTok, Twitch, Kick | Heavy | `08-platform-sources/index.md`, `youtube.md`, `tiktok.md`, `twitch.md`, `kick.md`, `99-agent-index.md` | heavy-complete | Added source-backed capture modes, setup notes, payload/event notes, app-vs-extension differences, support failures, and deeper extraction targets. | +| 2026-06-24 | Codex | Product map, install surfaces, API, common FAQ, custom/source development | Heavy | `01-product-map.md`, `02-installation-and-surfaces.md`, `09-api-and-integrations/websocket-http-api.md`, `11-support-kb/common-questions.md`, `08-platform-sources/generic-and-custom-sources.md`, `12-development/adding-a-source.md`, indexes | heavy-complete | Source-backed pass using README, api.md, parameters.md, commands docs, download docs, site metadata, manifest/source patterns, custom script templates, and sample WSS source. Support DB mining remains pending. | +| 2026-06-24 | Codex | Overlay pages, TTS, AI, OBS, StreamDeck/Companion, capture/display troubleshooting | Heavy | `07-overlays-and-pages/dock.md`, `featured.md`, `index.md`, `09-api-and-integrations/tts.md`, `ai-features.md`, `obs.md`, `streamdeck-companion.md`, `10-troubleshooting/extension-not-capturing.md`, `obs-overlay-display.md`, indexes | heavy-complete | Added source-backed setup modes, command/control references, free-vs-paid AI/TTS boundaries, OBS audio/control notes, and troubleshooting matrices. Needs line-level behavior and support DB mining later. | +| 2026-06-24 | Codex | Support KB mining method, historical issue map, stale-claim register, platform known-issue matrix | Heavy | `11-support-kb/mining-method.md`, `historical-issues.md`, `unresolved-or-stale-claims.md`, `support-source-map.md`, `10-troubleshooting/platform-known-issues.md`, indexes | heavy-complete | Safe support-source pass using curated instructions, generated top issues, Q&A exports, playbooks, SQLite schemas/counts, and topic-frequency queries. Raw archive was schema/count checked only; no raw conversation extraction. | +| 2026-06-24 | Codex | Desktop app issues, auth/sign-in, settings loss and backups | Heavy | `10-troubleshooting/desktop-app-issues.md`, `auth-and-sign-in.md`, `settings-loss-and-backups.md`, indexes | heavy-complete | Source-backed pass using `ssapp/main.js`, `state.js`, OAuth handlers, backup/transfer modules, and settings diagnostics. Does not include real in-app/e2e testing. | +| 2026-06-24 | Codex | Event Flow, Streamer.bot, Rumble, Facebook, Instagram, Discord | Heavy | `09-api-and-integrations/event-flow-editor.md`, `streamerbot.md`, `08-platform-sources/rumble.md`, `facebook.md`, `instagram.md`, `discord.md`, indexes | heavy-complete | Source-backed pass using Event Flow editor/system/tests/guides, Streamer.bot setup page, Rumble DOM/API bridge, Facebook DOM/Graph bridge, Instagram live/feed scripts, and Discord content script. Needs line-level/intense validation later. | +| 2026-06-24 | Codex | Multi-alerts, waitlist/polls/timer/giveaway/games, custom overlays | Heavy | `07-overlays-and-pages/multi-alerts.md`, `waitlist-polls-games.md`, `custom-overlays.md`, indexes | heavy-complete | Source-backed pass using `multi-alerts.*`, `waitlist.html`, `poll.html`, `timer.html`, `giveaway*.html`, `games.html`, `docs/customoverlays.md`, `sampleoverlay.html`, and `api.md`. Needs per-game and command-handler intense checks later. | +| 2026-06-24 | Codex | Development repo map, shared code rules, testing, build/release boundaries | Heavy | `12-development/index.md`, `repo-map.md`, `shared-code-rules.md`, `testing-and-validation.md`, `build-and-release-boundaries.md`, `99-agent-index.md` | heavy-complete | Source-backed pass using `social_stream/AGENTS.md`, `manifest.json`, package scripts, `ssapp/AGENTS.md`, `ssapp/package.json`, `ssapp/RELEASE.md`, and app resource notes. | +| 2026-06-24 | Codex | Cross-cutting reference pages for commands, URL options, modes, costs, plugin paths, and support resources | Heavy | `13-reference/index.md`, `commands-and-actions.md`, `url-parameters.md`, `modes-and-capability-matrix.md`, `free-paid-and-support-boundaries.md`, `custom-plugins-and-extensions.md`, `support-resources-and-escalation.md`, `99-agent-index.md` | heavy-complete | Source-backed reference pass using README, `api.md`, `parameters.md`, `docs/commands.html`, support/download/guides pages, custom script templates, source/dev docs, and current agent pages. Needs line-level/intense validation against command handlers, settings definitions, and page-specific parameter parsing. | +| 2026-06-24 | Codex | Supported-site and source inventory | Heavy | `08-platform-sources/source-inventory.md`, `08-platform-sources/index.md`, `99-agent-index.md`, `01-extraction-checklist.md` | heavy-complete | Parsed `docs/js/sites.js`, `manifest.json`, `sources/*.js`, `sources/static/*`, `sources/inject/*`, and `sources/websocket/*` into counts and public setup groups. Needs generated manifest-to-site mapping and health/status reconciliation later. | +| 2026-06-24 | Codex | Generated settings, toggles, URL parameter counts, and feature capability map | Heavy | `13-reference/settings-and-toggles.md`, `features-and-capabilities.md`, `13-reference/index.md`, `11-support-kb/common-questions.md`, indexes | heavy-complete | Parsed `shared/config/settingsDefinitions.js` and `shared/config/urlParameters.js`; mapped 327 popup settings, 255 generated URL parameters, generated setting categories, and public feature families from `docs/features.html`. Needs line-level storage/live-update/app-parity validation later. | +| 2026-06-24 | Codex | Manifest source-load matrix and provider/shared utility map | Heavy | `08-platform-sources/manifest-content-scripts.md`, `12-development/provider-cores-and-shared-utils.md`, indexes | heavy-complete | Parsed `manifest.json` content-script buckets, special `document_start`/`all_frames` entries, web-accessible provider/shared resources, and provider-core exports for Kick, Twitch, and YouTube. Needs full 155-row public-site mapping and adapter/event-payload tracing later. | ## Master Checklist ### Product And Existing Docs -- [ ] Quick: `social_stream/README.md`, `about.md`, `ai.md` -- [ ] Heavy: product surfaces, install modes, extension/app differences +- [x] Quick: `social_stream/README.md`, `about.md`, `ai.md` +- [x] Heavy: product surfaces, install modes, extension/app differences - [ ] Intense: verify all claims against current code and public docs -- [ ] Quick: `social_stream/api.md`, `parameters.md`, `docs/event-reference.html` -- [ ] Heavy: API commands, URL params, event schema, message payload contract +- [x] Quick: `social_stream/api.md`, `parameters.md`, `docs/event-reference.html` +- [x] Heavy: API commands, URL params, event schema, message payload contract +- [x] Heavy: cross-topic reference pages for command/action buckets, URL parameter families, mode selection, free/paid boundaries, plugin/custom paths, and support resources +- [x] Heavy: generated setting category map, popup/URL setting distinction, and broad feature/capability routing - [ ] Intense: field-by-field payload and command behavior with source references - [ ] Quick: `social_stream/docs/*.html`, `social_stream/docs/*.md` @@ -96,24 +110,30 @@ Add one entry per extraction pass. - [ ] Heavy: extension lifecycle, background routing, storage, source capture, messaging - [ ] Intense: source-to-dock message flow and external API behavior -- [ ] Quick: `popup.html`, `popup.js`, `settings/*`, `shared/config/*` -- [ ] Heavy: settings UI, storage keys, session/password behavior, generated parameter docs +- [x] Heavy: manifest content-script buckets, source-load flags, and helper/source-page classification + +- [x] Quick: `popup.html`, `popup.js`, `settings/*`, `shared/config/*` +- [x] Heavy: settings UI, storage keys, session/password behavior, generated parameter docs - [ ] Intense: settings migration, sync/local behavior, app parity ### Shared Pages And Overlays -- [ ] Quick: `dock.html`, `featured.html`, `multi-alerts.*`, `tts.*` -- [ ] Heavy: dock controls, featured overlay, alert routing, TTS behavior +- [x] Quick: `dock.html`, `featured.html`, `multi-alerts.*`, `tts.*` +- [x] Heavy: dock controls, featured overlay, alert routing, TTS behavior, waitlist/poll/timer/giveaway/games, and custom overlays - [ ] Intense: OBS/browser-source troubleshooting and payload/rendering edge cases -- [ ] Quick: overlay/tool pages listed in `02-resource-manifest.md` -- [ ] Heavy: high-use pages only: waitlist, poll, timer, tipjar, giveaway, actions, chatbot/cohost +- [x] Quick: overlay/tool pages listed in `02-resource-manifest.md` +- [x] Heavy: high-use pages only: waitlist, poll, timer, giveaway, actions/Event Flow, custom overlays, multi-alerts - [ ] Intense: only pages tied to frequent support issues or APIs ### Platform Sources - [ ] Quick: all active `social_stream/sources/*.js` -- [ ] Heavy: YouTube, TikTok, Twitch, Kick, Facebook, Instagram, Rumble, Discord, generic/custom sources +- [x] Heavy: public supported-site/source inventory counts and setup-type groups +- [x] Heavy: manifest content-script source-load matrix and special load flags +- [x] Heavy: YouTube, TikTok, Twitch, Kick +- [x] Heavy: Facebook, Instagram, Rumble, Discord +- [x] Heavy: generic/custom sources - [ ] Intense: TikTok, YouTube, Kick, Twitch, and any platform with recurring support failures - [ ] Quick: `social_stream/sources/websocket/*` @@ -121,31 +141,34 @@ Add one entry per extraction pass. - [ ] Intense: YouTube, TikTok-adjacent app behavior, Kick, Twitch EventSub, Rumble - [ ] Quick: `social_stream/providers/*`, `shared/*` -- [ ] Heavy: provider core responsibilities and extension/app compatibility rules +- [x] Heavy: provider core responsibilities and extension/app compatibility rules - [ ] Intense: provider cores used by fragile/high-value integrations ### Event Flow And Integrations -- [ ] Quick: `actions/*` -- [ ] Heavy: Event Flow Editor, triggers, actions, state nodes, tests +- [x] Quick: `actions/*` +- [x] Heavy: Event Flow Editor, triggers, actions, state nodes, tests - [ ] Intense: custom JS actions, media actions, Kick rewards, OBS actions -- [ ] Quick: `api.md`, `streamerbot.html`, `obs-websocket-test.html`, StreamDeck/Companion sections -- [ ] Heavy: integration setup, command paths, troubleshooting +- [x] Quick: `api.md`, `streamerbot.html`, `obs-websocket-test.html`, StreamDeck/Companion sections +- [x] Heavy: integration setup, command paths, troubleshooting - [ ] Intense: API command contract and OBS remote-control behavior +- [x] Heavy: TTS providers, AI features, OBS integration, StreamDeck/Companion control +- [ ] Intense: provider/API behavior, OBS control paths, and command contract from line-level code + ### Standalone App - [ ] Quick: `ssapp/README.md`, `RELEASE.md`, `package.json` -- [ ] Heavy: app surfaces, build/run commands, release boundaries +- [x] Heavy: app build/run commands and release boundaries from `AGENTS.md`, `RELEASE.md`, and `package.json` - [ ] Intense: release docs only if doing release-related docs -- [ ] Quick: `ssapp/main.js`, `preload.js`, `state.js`, `index.html`, `renderer.js` -- [ ] Heavy: Electron app architecture, source loading, IPC, state persistence +- [x] Quick: `ssapp/main.js`, `preload.js`, `state.js`, `index.html`, `renderer.js` +- [x] Heavy: Electron app architecture, source loading, IPC, state persistence - [ ] Intense: settings loss, source resolution, security/path validation, message bridge -- [ ] Quick: `ssapp/resources/electron-*-handler.js`, `kick-ws-client.js` -- [ ] Heavy: OAuth and platform handlers +- [x] Quick: `ssapp/resources/electron-*-handler.js`, `kick-ws-client.js` +- [x] Heavy: OAuth and platform handlers - [ ] Intense: YouTube/Twitch/Facebook/Kick/Velora/VPZone auth flows - [ ] Quick: `ssapp/tiktok/*`, `ssapp/tiktok-signing/*`, `ssapp/tests/tiktok/*` @@ -154,27 +177,34 @@ Add one entry per extraction pass. ### Support Knowledge Base -- [ ] Quick: `stevesbot/resources/instructions/social-stream-support.md` -- [ ] Heavy: support answer style, top recurring advice, escalation rules +- [x] Quick: `stevesbot/resources/instructions/social-stream-support.md` +- [x] Heavy: support answer style, top recurring advice, escalation rules - [ ] Intense: verify every user-facing troubleshooting claim against code/docs -- [ ] Quick: `stevesbot/resources/learnings/social-stream-ninja-top-issues.md` -- [ ] Heavy: common issues and platform-specific support history +- [x] Quick: `stevesbot/resources/learnings/social-stream-ninja-top-issues.md` +- [x] Heavy: common issues and platform-specific support history - [ ] Intense: stale/historical claim review -- [ ] Quick: SSN files in `stevesbot/resources/learnings/support-qa/*` -- [ ] Heavy: common Q&A extraction into troubleshooting pages +- [x] Quick: SSN files in `stevesbot/resources/learnings/support-qa/*` +- [x] Heavy: common Q&A extraction into troubleshooting pages - [ ] Intense: scenario-by-scenario validation against current source -- [ ] Quick: `stevesbot/data/sqlite/knowledge.sqlite` and `resources/knowledge.sqlite` -- [ ] Heavy: category/platform/product queries for SSN support issues +- [x] Quick: repo-backed common questions from `README.md`, `api.md`, `parameters.md`, and public docs +- [x] Heavy: repo-backed common questions and support triage baseline +- [x] Heavy: historical support method, issue map, stale claim register, and platform known-issues matrix +- [x] Heavy: support resource routing, escalation criteria, and bug-report evidence checklist +- [ ] Intense: resolve stale/contradictory claims against current source + +- [x] Quick: `stevesbot/data/sqlite/knowledge.sqlite` +- [ ] Quick: `stevesbot/resources/knowledge.sqlite` +- [x] Heavy: category/platform/product queries for SSN support issues - [ ] Intense: high-frequency platform support threads and contradiction checks -- [ ] Quick: `stevesbot/data/sqlite/stevesbot.sqlite` -- [ ] Heavy: curated support records and Q&A entries +- [x] Quick: `stevesbot/data/sqlite/stevesbot.sqlite` +- [x] Heavy: curated support records and Q&A entries - [ ] Intense: only for high-risk/high-volume claims -- [ ] Quick: `stevesbot/data/sqlite/archive.sqlite` +- [x] Quick: `stevesbot/data/sqlite/archive.sqlite` - [ ] Heavy: raw message search only to confirm real-world symptom wording or frequency - [ ] Intense: anonymized deep dives only for unresolved or unclear support issues @@ -184,8 +214,9 @@ Add one entry per extraction pass. - [ ] Heavy: expected behavior and testable workflows - [ ] Intense: only for features with current E2E coverage or fragile regressions -- [ ] Quick: `ssapp/tests/electron/*`, `ssapp/tests/tiktok/*` -- [ ] Heavy: app regression expectations and diagnostics +- [x] Quick: `ssapp/tests/electron/*` +- [ ] Quick: `ssapp/tests/tiktok/*` +- [x] Heavy: app regression expectations and diagnostics - [ ] Intense: settings loss, source URL parsing, TikTok connection behavior ## Row Template For New Detailed Tracking diff --git a/docs/agents/01-product-map.md b/docs/agents/01-product-map.md index b98090213..b2a016bb2 100644 --- a/docs/agents/01-product-map.md +++ b/docs/agents/01-product-map.md @@ -1,35 +1,148 @@ # SSN Product Map -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started from public repo docs and app docs. This is the orientation page for future AI documentation passes. -## Purpose +## Source Anchors -This page explains what Social Stream Ninja is, what surfaces it includes, and how those surfaces fit together for live chat capture, dashboards, overlays, automation, TTS, and AI tools. +- `README.md` +- `api.md` +- `parameters.md` +- `docs/features.html` +- `docs/download.html` +- `docs/commands.html` +- `docs/ssapp.html` +- `docs/js/sites.js` +- `C:\Users\steve\Code\ssapp\AGENTS.md` -## Source Anchors +## What Social Stream Ninja Is + +Social Stream Ninja is a free, open-source live-chat capture and overlay ecosystem. It consolidates chat, events, donations, and automation across many platforms and exposes the data to docks, featured overlays, alert pages, bots, APIs, and external production tools. + +Public repo docs describe the product as: + +- Browser extension or standalone desktop app. +- 120+ supported sites and growing. +- Built around VDO.Ninja peer-to-peer transport, with optional API server workflows. +- Open API for control and data access. +- Featured chat overlay and dock workflow. +- AI and TTS integrations. +- Scriptable customization and custom overlay support. + +## Primary Surfaces + +| Surface | Role | Typical User | +| --- | --- | --- | +| Browser extension | Captures messages from supported browser pages and popout chats | Streamers already using Chrome/Edge/Brave/Firefox sessions | +| Standalone desktop app | Electron app that manages sources and loads Social Stream code without browser extension install | Users who want source management, app windows, and fewer browser throttling issues | +| Dock (`dock.html`) | Main control/dashboard page for chat, queueing, pinning, filtering, chat sending, TTS controls, and source state | Streamer/moderator/operator | +| Featured overlay (`featured.html`) | Shows selected/featured chat messages | OBS/production output | +| Alert/tool pages | Waitlist, polls, games, tip jar, credits, emotes, multi-alerts, timers, AI/bot/cohost pages | Streamer production extras | +| Hosted pages | Current hosted versions on `socialstream.ninja` | Normal users and OBS browser sources | +| Local/forked pages | Local files or fork-hosted pages | Advanced customization and development | +| Lite web app | Lightweight web-only option | Quick/mobile/limited workflows | +| External API clients | StreamDeck, Companion, bots, private apps, donation webhooks | Automation developers/operators | + +## Extension vs Standalone App + +Use the extension when: + +- The site works best with normal browser cookies/login/session. +- A platform blocks embedded app sign-in. +- The user wants Chrome Web Store/manual extension behavior. +- The user already has popout chats open in their browser workflow. + +Use the standalone app when: + +- The user wants source windows managed in one app. +- The workflow suffers from Chrome background throttling or minimized windows. +- Always-on-top or transparent app-window behavior is useful. +- Extension install/policy restrictions are a problem. + +Boundary from `ssapp` instructions: + +- Source edits belong in `C:\Users\steve\Code\social_stream`. +- The standalone app loads Social Stream source files remotely from that repo at app startup. +- `ssapp/resources/social_stream_fallback` is a rebuilt fallback bundle, not the primary source. + +## Core User Workflow + +1. Install/launch the extension or standalone app. +2. Enable the source/capture mode needed for the platform. +3. Open the supported chat page, popout chat, or source page. +4. Open `dock.html` with the same session ID. +5. Open `featured.html` or another overlay in OBS with the same session ID. +6. Select/queue/pin messages in the dock or allow auto-show rules. +7. Add optional TTS, AI, Event Flow, API, waitlist, polls, tip jar, or graphics integrations. + +Most support issues reduce to a mismatch in one of those steps: wrong surface, wrong source mode, wrong session ID, hidden/minimized source, missing toggle, or stale page. + +## Supported Sites + +The README states 120+ supported sites. `docs/js/sites.js` currently lists 139 named entries and classifies them into standard, popout, toggle-required, WebSocket-source, and manual-pick setup types. + +The implementation source of truth is: + +- `manifest.json` for extension URL matching. +- `sources/*.js` for DOM/manual/static capture. +- `sources/websocket/*` for source-page/API/socket capture. +- `providers/*` and `shared/*` for shared provider/runtime logic. + +Do not promise a site is working from the README list alone. Check the source file and recent support history for active breakages. + +## Message Flow In One Paragraph + +A source captures a platform message or event, builds an SSN message object, sends it to the extension/app background processing path, optional filters/bots/AI/custom user functions modify it, and the resulting payload is delivered through peer-to-peer or API-server routing to docks, overlays, alert pages, and external listeners. + +See `05-message-flow-and-event-contracts.md` for the payload contract and `09-api-and-integrations/websocket-http-api.md` for remote-control/listener workflows. + +## Customization Layers + +From simplest to most invasive: + +1. URL parameters: style, filters, queueing, TTS, API routing, labels, OBS/graphics options. +2. OBS browser-source CSS: fastest safe visual override. +3. Hosted/forked/local custom overlay: full visual control. +4. `custom.js`: local dock/featured custom behavior. +5. Uploaded `window.customUserFunction`: message processing/filter/reply logic. +6. API/WebSocket source: external app sends SSN-shaped messages. +7. New source file: first-class platform integration. + +## Automation And Integrations + +Main integration families: + +- HTTP/WebSocket API for StreamDeck, custom apps, and bots. +- Bitfocus Companion module. +- MIDI hotkeys. +- Donation webhooks for Stripe, Ko-Fi, Buy Me A Coffee, and Fourthwall. +- OBS remote/scene support through browser-source permissions and URL parameters. +- H2R, SPX-GC, Singular.live, generic POST/PUT integrations. +- AI chatbot/moderation/cohost features through local or cloud providers. +- TTS through browser/system voices, local/browser providers, or cloud providers. + +## Free vs Paid Boundaries -- `C:\Users\steve\Code\social_stream\README.md` -- `C:\Users\steve\Code\social_stream\about.md` -- `C:\Users\steve\Code\social_stream\docs\features.html` -- `C:\Users\steve\Code\social_stream\docs\ssapp.html` -- `C:\Users\steve\Code\ssapp\README.md` -- `C:\Users\steve\Code\stevesbot\resources\instructions\social-stream-support.md` +SSN itself is free/open-source. Costs can appear when: -## Starter Notes +- A third-party TTS/AI provider requires an account/API key/billing. +- A platform feature is paywalled by the platform. +- The user pays for unrelated production tools such as graphics systems or hosted services. -SSN has at least two primary delivery surfaces: the Chrome extension and the standalone Electron app. The extension captures chat from many platform pages through browser scripts. The standalone app wraps the same Social Stream source files inside Electron and adds app-specific source management, OAuth helpers, persistence behavior, and platform glue. +Do not describe third-party services as free unless the current provider docs/code confirm it. The SSN docs note that free tiers and provider availability vary. -Public overlay/tool pages such as `dock.html`, `featured.html`, alert pages, games, TTS pages, and API examples are part of the same ecosystem. Some pages are shipped with the extension, some are hosted, and some are used by the app. +## Related But Separate Projects -## Planned Sections +Mention related projects only when they matter to a support answer: -- What SSN does -- Chrome extension vs standalone app -- Hosted pages vs packaged pages -- OBS workflow overview -- Source windows, dashboard, featured overlay, and optional tools -- AI/cohost, TTS, Event Flow, and external integrations +- VDO.Ninja: underlying transport inspiration/integration and related remote-control workflows. +- Electron Capture: separate app sometimes suggested for always-on-top browser windows. +- `ssapp` / `ssn_app`: standalone desktop app source repo. +- Lite: web app with limited feature set. -## Open Questions +## Open Documentation Gaps -- Which related products should be included in this product map: Electron Capture, Caption.Ninja, VDO.Ninja bridge, or only SSN proper? +- Exact current status of each site source. +- Full overlay/page catalog with every parameter and message contract. +- Feature matrix comparing extension, app, hosted, local, Firefox, MV3, and Lite. +- AI/TTS provider setup matrix. +- Mined Discord/KB historical issue frequency. diff --git a/docs/agents/02-installation-and-surfaces.md b/docs/agents/02-installation-and-surfaces.md index ccd74d5e5..7472ef8b4 100644 --- a/docs/agents/02-installation-and-surfaces.md +++ b/docs/agents/02-installation-and-surfaces.md @@ -1,35 +1,223 @@ # Installation And Surfaces -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started from README/download/app docs. -## Purpose +## Source Anchors -This page documents how users install, open, update, and choose between SSN surfaces: Chrome extension, standalone app, hosted pages, local pages, beta builds, and source/development mode. +- `README.md` +- `docs/download.html` +- `docs/ssapp.html` +- `docs/commands.html` +- `C:\Users\steve\Code\ssapp\AGENTS.md` +- `C:\Users\steve\Code\ssapp\package.json` +- `C:\Users\steve\Code\ssapp\RELEASE.md` -## Source Anchors +## Install Choices + +| Choice | Best For | Main Limits | +| --- | --- | --- | +| Chrome Web Store extension | Easiest install for Chromium users | Store review means it can lag GitHub; MV3 restrictions apply. | +| Manual unpacked extension | Latest code, development, advanced users | Manual update required; do not uninstall to update. | +| Firefox XPI | Firefox users | Missing some Chromium-only features, including debugger/tab capture behaviors and some TTS/model features. | +| Standalone app | Users who want app-managed sources and no browser extension | Embedded sign-in can be blocked by some platforms; app behavior needs real app testing. | +| Hosted pages | Normal OBS/dock/featured use | Cannot load local-only custom files like a local `custom.js`. | +| Local/forked pages | Advanced customization and source work | User must manage updates and local path quirks. | +| Lite web app | Quick/mobile/lightweight sessions | Very limited features and customization. | + +## Manual Extension Install + +Current public flow: + +1. Download the GitHub source archive. +2. Extract it into a folder. +3. Open the browser extensions page: + - Chrome: `chrome://extensions/` + - Edge: `edge://extensions/` + - Brave: `brave://extensions/` +4. Enable Developer Mode. +5. Click Load unpacked. +6. Select the extracted Social Stream folder. +7. Reload any already-open chat pages. + +Support reminders: + +- Extension icon red means off; green means enabled. +- Reload source chat pages after extension reload/update. +- Keep the extracted folder in place. Moving/deleting it breaks the unpacked extension. + +## Updating The Extension + +Do: + +- Download new files. +- Replace the old files. +- Reload the extension or restart the browser. +- Reload source chat pages. + +Do not: + +- Uninstall just to update. + +Reason: uninstalling deletes extension settings. If uninstall is required, export settings first and import them after reinstalling. + +## Browser Store Builds + +Chrome Web Store: + +```text +https://chromewebstore.google.com/detail/social-stream-ninja/cppibjhfemifednoimlblfcmjgfhfjeg +``` + +Firefox direct XPI: + +```text +https://raw.githubusercontent.com/steveseguin/social_stream/firefox/social-stream-ninja.xpi +``` + +The README says the Chrome Web Store build is updated every few weeks because of review restrictions. For newest features/fixes, use manual GitHub install. + +## Manifest Version Notes + +The README says Manifest V2 warnings can be ignored for current function. Manifest V3 exists and is used by Chrome Web Store builds, but the README notes MV3 may require a small browser tab to remain open. + +When debugging an extension issue, record whether the user is on: + +- Manual MV2/unpacked. +- Manual MV3 branch/build. +- Chrome Web Store MV3. +- Firefox XPI. + +Do not assume all features are available across those surfaces. + +## Firefox Limits + +Current public docs mention Firefox limitations: + +- Some TTS voice/model support is missing or limited. +- Tab capture/debugger-dependent features are not available. +- Auto-responder/debugger behavior should be treated as Chromium-only unless current code says otherwise. + +Ask Firefox users to reproduce in Chrome/Edge when diagnosing source capture or auto-response features that depend on Chromium APIs. + +## Standalone App Install + +The download page points Windows, macOS, and Linux app downloads to Social Stream release assets: + +```text +https://github.com/steveseguin/social_stream/releases +``` + +Download-page notes: + +- Windows: Windows 10/11 x64. +- macOS: standalone desktop app. +- Linux: AppImage, limited support. +- No browser extension required. +- App docs say standalone builds automatically update. + +Repo boundary: + +- App code lives in `C:\Users\steve\Code\ssapp`. +- Social Stream source edits still belong in `C:\Users\steve\Code\social_stream`. +- Do not use `ssapp/resources/social_stream_fallback` as the source of truth. + +## Choosing Extension vs App + +Recommend extension first when: + +- Platform login/session is already working in Chrome/Edge/Brave. +- The source needs normal browser cookies. +- The user relies on a Chrome extension workflow. +- The user is testing whether a site still works with the canonical extension source. + +Recommend standalone app when: + +- Browser windows are getting throttled or discarded. +- The user wants app-managed source windows. +- The user wants always-on-top/transparent source viewing. +- The user cannot or does not want to install an extension. +- Source organization matters more than sharing a normal browser login. + +Warn that some platforms block embedded sign-in or behave differently in Electron. If a sign-in fails in app mode, verify the same source in a normal browser extension before treating it as a source-code bug. + +## Hosted Pages + +Common hosted pages: + +- `https://socialstream.ninja/dock.html?session=SESSION` +- `https://socialstream.ninja/featured.html?session=SESSION` +- `https://socialstream.ninja/sampleapi.html?session=SESSION` +- `https://socialstream.ninja/sampleoverlay?session=SESSION` +- `https://socialstream.ninja/actions/` +- `https://socialstream.ninja/docs/` + +Hosted pages are usually the right answer for OBS browser sources and normal users because they stay current. + +Limit: + +- Hosted pages cannot load a local `custom.js` file from the user's disk. + +## Local/Forked Pages + +Use local or forked pages when: + +- Building a custom overlay from scratch. +- Testing source changes. +- Loading local `custom.js`. +- Running a fork with stream-specific changes. + +Risks: + +- The user must update local files manually. +- Local-file behavior differs by OS and browser. +- README notes OBS local-file CSS/page behavior can be problematic on macOS/Linux. +- If the user edits files in an installed/unpacked extension folder, updates may overwrite local changes. + +## Lite Web App + +Download docs describe Lite as: + +- No install needed. +- Lightweight and usable on mobile. +- Extremely limited feature set and customization options. +- Supports only a handful of core services. +- Useful for quick checks, not full production parity. + +Do not use Lite docs to answer full extension/app questions unless the user is explicitly using Lite. + +## Development/Source Mode + +For Social Stream extension/source development: + +- Work in `C:\Users\steve\Code\social_stream`. +- Load unpacked extension from that folder or a build-specific folder. +- Use local/localhost source pages where manifest entries support them. +- Use `scripts/validate-configs.sh` before commits/pushes that touch settings/config JSON. -- `social_stream/README.md` -- `social_stream/docs/download.html` -- `social_stream/docs/ssapp.html` -- `ssapp/README.md` -- `ssapp/package.json` -- `ssapp/RELEASE.md` +For standalone app development: -## Starter Notes +- Work in `C:\Users\steve\Code\ssapp`. +- Read `ssapp/AGENTS.md` and `RELEASE.md` before release work. +- Run app behavior in the actual Electron app for real validation. -The Chrome extension and standalone app are not interchangeable in every workflow. The extension runs in Chrome and benefits from normal browser login sessions. The app runs in Electron and can manage sources without the extension, but some embedded sign-in flows can be blocked by platforms. +## First Support Questions -## Planned Sections +When a user says "SSN is installed but not working", ask or infer: -- Chrome extension install and update -- Browser store installs -- Manual unpacked extension install -- Standalone app install -- Stable vs beta -- Hosted overlay URLs -- Local/source mode for development -- When to recommend extension vs app +- Which surface: extension, standalone app, Lite, hosted overlay, local page? +- Which browser/app version/install source? +- Which source platform and URL pattern? +- Is the extension/app enabled? +- Is the source page reloaded after install/update? +- Is the chat page visible and not minimized? +- Does dock/overlay use the same session ID? +- Are toggle-required sources enabled? +- Is the user expecting a feature unavailable in Firefox, Lite, MV3, or app mode? -## Open Questions +## Open Documentation Gaps -- Which install/update paths should be treated as current primary guidance? +- Exact stable/beta branch guidance for every distribution path. +- Current auto-update behavior by OS/app channel. +- Full Firefox feature matrix. +- Full MV2/MV3 behavior matrix. +- App sign-in limitations by platform. diff --git a/docs/agents/07-overlays-and-pages/custom-overlays.md b/docs/agents/07-overlays-and-pages/custom-overlays.md index b8f8089db..004fe06c7 100644 --- a/docs/agents/07-overlays-and-pages/custom-overlays.md +++ b/docs/agents/07-overlays-and-pages/custom-overlays.md @@ -1,29 +1,264 @@ # Custom Overlays -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started on 2026-06-24. ## Purpose -Document how custom overlays consume SSN messages and how users can style or build their own pages safely. +Document how to build custom SSN overlay pages that receive normalized SSN messages without modifying the extension background/runtime code. ## Source Anchors - `social_stream/docs/customoverlays.md` - `social_stream/docs/event-reference.html` - `social_stream/sampleoverlay.html` -- `social_stream/samplefeatured.html` +- `social_stream/themes/sampleoverlay_reverse.html` - `social_stream/themes/**` -## Starter Notes +## Recommended Pattern -Custom overlays commonly use either WebSocket/API connection methods or the hidden VDO.Ninja iframe bridge. Existing repo instructions prefer preserving payload structure and using URL-driven CSS/settings when possible. +For visual browser/OBS overlays, prefer the hidden VDO.Ninja iframe bridge. This matches the built-in overlays and avoids requiring direct WebSocket handling in simple custom pages. -## Planned Sections +Core URL inputs: -- Message listener patterns -- VDO.Ninja bridge -- WebSocket API -- CSS customization -- Payload compatibility -- Examples -- Common mistakes +- `session`: required SSN session ID. +- `password`: optional session password. +- `label`: usually `dock` for normal chat/events unless the overlay is meant to receive targeted messages. + +Typical iframe pattern: + +```text +https://vdo.socialstream.ninja/?ln&salt=vdo.ninja&password=PASSWORD&view=SESSION&label=dock&noaudio&novideo&cleanoutput&room=SESSION +``` + +Built-in overlays often also use: + +- `push` +- `vd=0` +- `ad=0` +- `autostart` +- `notmobile` +- `solo` + +Use the existing page closest to the desired behavior as the source example. + +## Message Listener Pattern + +Custom pages should listen for messages from the iframe and verify the source: + +```javascript +window.addEventListener("message", function (event) { + if (event.source !== iframe.contentWindow) return; + if (event.data && + event.data.dataReceived && + event.data.dataReceived.overlayNinja) { + processIncomingSSNMessage(event.data.dataReceived.overlayNinja); + } +}); +``` + +Do not accept every `window.postMessage` event blindly. Other frames/pages can send messages too. + +## Payload Shape + +Normal chat/event payloads commonly include: + +- `type` +- `chatname` +- `chatmessage` +- `chatimg` +- `chatbadges` +- `nameColor` +- `hasDonation` +- `membership` +- `contentimg` +- `event` +- `userid` +- `bot` +- `mod` +- `host` +- `vip` +- `tid` +- `meta` + +Agents should keep payload compatibility broad. Fields vary by platform and event. A custom overlay should be resilient when optional fields are missing. + +Important rule from existing docs: reserve `event` for system notifications or action/event payloads. Normal chat messages should leave `event` unset or false so overlays do not mistake chat for alerts. + +## WebSocket Pattern + +WebSocket mode is more advanced and better for tools or integrations than simple visual overlays. + +Common server: + +```text +wss://io.socialstream.ninja +``` + +API variant used by several tool pages: + +```text +wss://io.socialstream.ninja/api +``` + +Extension variant used by several pages: + +```text +wss://io.socialstream.ninja/extension +``` + +For receiving normal extension messages, examples commonly join with: + +```json +{ "join": "SESSION", "out": 3, "in": 4 } +``` + +Some tools use different channels. Do not reuse channel pairs blindly; copy from the closest built-in page. + +## Sending Commands Back + +Custom pages can send payloads back through the iframe: + +```javascript +iframe.contentWindow.postMessage({ + sendData: { overlayNinja: commandObject }, + type: "pcs" +}, "*"); +``` + +For targeted replies to a specific peer, some built-in tools use `type: "rpcs"` and a `UUID`. + +Only send commands when the receiving page/background path is known to handle them. A chat overlay should not invent new command shapes without corresponding runtime support. + +## Sample Overlay Behavior + +`sampleoverlay.html` is a chat overlay example with source comments for AI/code editing. + +It supports: + +- `session` +- `password` +- `reverse` +- `deleteonlylast` +- `limit`, default 20 +- `showtime`, default 30000 ms +- `fadezone` +- `server` +- `server2` +- `localserver` + +It renders: + +- avatar +- name +- source icon +- badges +- membership +- chat text +- donation +- content image + +It removes oldest messages after `limit`, fades old messages after `showtime`, and supports reverse mode where new messages insert at the top. + +The WebSocket fallback joins: + +```json +{ "join": "SESSION", "out": 3, "in": 4 } +``` + +## Reverse Sample + +`themes/sampleoverlay_reverse.html` is a reverse-scroll variant. It keeps newest messages pinned to the top and pushes older messages downward. Its source comments warn not to modify the scroll logic without testing. + +Use this when a user wants top-down chat rather than the default bottom-up stack. + +## Styling Options + +Custom overlays should prefer URL-driven styling and CSS variables where practical. + +Common parameters to support or copy from existing overlays: + +- `css`: external CSS URL. +- `base64css`, `b64css`, `cssbase64`, `cssb64`: embedded CSS. +- `font` +- `googlefont` +- `scale` +- `limit` +- `showtime` +- `fadeout` +- `hidesource` +- `onlytype` +- `hidetype` +- `sources` +- `hidesources` +- `sourceids` +- `hidesourceids` +- `donationsonly` +- `eventsonly` +- `hidebots` + +Not all built-in overlays support all of these. They are common conventions, not a guaranteed global standard. + +## Security And Safety + +Use `textContent` for untrusted user text unless the overlay intentionally supports SSN's already-normalized HTML/emote markup. + +If inserting `chatmessage` with `innerHTML`, remember: + +- Some source scripts preserve HTML for emotes/images when text-only mode is off. +- Custom user-generated HTML can create XSS risk if not sanitized. +- Use a sanitizer or strict rendering logic if the page is shared publicly. + +Always validate: + +- `event.source` for iframe messages. +- Payload shape before reading fields. +- Image URLs before blindly inserting them into style attributes. + +Do not modify `background.js` for a normal custom overlay. Build against the existing message bridge and payload contract. + +## Performance Rules + +For active streams: + +- Cap displayed messages. +- Remove old DOM nodes. +- Batch expensive layout updates. +- Avoid synchronous work in every message when chat volume can spike. +- Keep image sizes constrained. +- Use CSS transitions rather than heavy JS animations. + +`sampleoverlay.html` is designed around these rules with max message count, fading, image limits, and controlled scroll transforms. + +## Common Mistakes + +Overlay receives nothing: + +- Missing or wrong `session`. +- Wrong `password`. +- Wrong `label`; use `dock` for normal chat unless targeting another feed. +- The source tab/app is not connected to the same session. + +Works in a browser but not OBS: + +- OBS Browser Source cache still has an old URL. +- Browser Source dimensions are too small. +- Local files may need a server if they import relative assets or hit browser restrictions. +- Audio autoplay/monitoring settings differ in OBS. + +Messages render as raw HTML or break layout: + +- Use text-only mode or sanitize before `innerHTML`. +- Limit image sizes. +- Handle missing fields. + +WebSocket overlay receives commands but not chat: + +- Wrong server endpoint or channel pair. +- SSN setting for sending chat to API server is disabled. +- Page joined the API channel but the extension is only sending through iframe/VDO path. + +## Remaining Extraction Targets + +- Extract common URL/filter parameters from `dock.html`, `featured.html`, and theme overlays into a custom overlay compatibility table. +- Review `samplefeatured.html` and other sample/theme pages if present in future passes. +- Add a minimal safe overlay template that uses `textContent` by default. diff --git a/docs/agents/07-overlays-and-pages/dock.md b/docs/agents/07-overlays-and-pages/dock.md index 1237473e4..3a701468c 100644 --- a/docs/agents/07-overlays-and-pages/dock.md +++ b/docs/agents/07-overlays-and-pages/dock.md @@ -1,29 +1,207 @@ # Dock Page -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started from `README.md`, `api.md`, `parameters.md`, and `dock.html`. -## Purpose +## Source Anchors -Document `dock.html`, the main dashboard/control page for viewing, filtering, selecting, sending, pinning, queueing, and routing messages. +- `dock.html` +- `api.md` +- `parameters.md` +- `README.md` +- `tts.js` +- `custom_sample.js` +- `docs/agents/09-api-and-integrations/websocket-http-api.md` -## Source Anchors +## Role + +`dock.html` is the operator dashboard and message control page. It is not just an overlay. It receives source messages, shows the consolidated chat feed, lets the operator feature/clear/queue/pin/block messages, sends chat responses where supported, controls TTS, and can forward selected messages to overlays or external integrations. + +Typical URL: + +```text +https://socialstream.ninja/dock.html?session=SESSION_ID +``` + +Support note: a white or empty dock is not automatically broken. It may simply have no messages yet, the wrong session, or no active source. + +## Required Setup + +- The source side must be running: browser extension, standalone app, WebSocket source page, or API sender. +- The dock `session` value must match the extension/app/source session. +- The extension/app must be enabled and source pages must be loaded/reloaded. +- For API-server operation, required API toggles must be enabled. +- For local `custom.js`, use a local/forked dock page that can load the local file. + +## Core Controls + +The README and `dock.html` confirm these user controls: + +| Control | Behavior | +| --- | --- | +| Click message | Feature/send selected message to the featured overlay. | +| Clear featured | Clears the featured overlay without necessarily clearing dock history. | +| Clear dock | Clears dock messages depending on mode/pinned state. | +| Auto-show | Automatically features incoming messages. | +| Queue | Hold CTRL on Windows/Linux or cmd on Mac and click a message to queue it. | +| Next in queue | Features the next queued message. | +| Pin | Hold ALT and click a message to pin/unpin it at the top. | +| TTS toggle | Starts/stops reading incoming messages where TTS is configured. | +| Chat composer | Sends chat replies to connected source pages where supported. | + +## Dashboard Modes + +Important URL parameters from `parameters.md` and `dock.html`: + +| Parameter | Meaning | +| --- | --- | +| `featuredmode` | Makes `dock.html` listen to the featured-message feed instead of all messages. | +| `chatmode` | Chat-only mode; hides pin/feature behavior. | +| `helpermode` | View/pin/queue mode without chat/feature controls. | +| `chatonly` | Moves chat input into the toolbar for a chat-centric layout. | +| `viewonly` | Disables chat, pin, and feature capabilities. | +| `queueonly` | Shows only queued messages. | +| `pinnedonly` | Shows only pinned messages. | +| `sync` / `synced` | Syncs message selection/deletion/pin/queue behavior across multiple docks. | +| `label` | Names this dock for targeted API commands. | + +Use these when one session has multiple operators, dashboards, or output pages. + +## Auto-Feature And Queue Parameters + +| Parameter | Meaning | +| --- | --- | +| `autoshow` | Auto-features incoming messages. | +| `autoshowtime` | Custom timing for auto-show. | +| `chartime` | Auto-show duration based on message length. | +| `autoshowdonos` | Auto-features donation messages only. | +| `autoshowmembers` | Auto-features member messages only. | +| `autoshowqueued` | Automatically advances queued messages. | +| `autoshowcontentimages` | Auto-features queued messages with images/content. | +| `autopindonations` | Pins donation cards as they arrive. | +| `autopinquestions` | Pins question cards as they arrive. | +| `autoqueuedonations` | Queues donation cards automatically. | +| `autoqueuequestions` | Queues question cards automatically. | +| `selfqueue` | Viewer command(s) that add a user/message to the queue. | +| `random` | Randomizes which queued message is featured next. | + +Support rule: when auto-show appears to skip messages, check filters, donation/member-only modes, queue settings, and source event type before assuming transport failure. + +## Display And Filter Parameters + +Common dock display parameters: + +- `lightmode` +- `darkmode` +- `scale` +- `compact` +- `showtime` +- `notime` +- `hidesource` +- `showsourcename` +- `noavatar` +- `nobadges` +- `striplinks` +- `hidecommands` +- `hidefrom` / `exclude` +- `onlyfrom` / `fromonly` +- `onlytwitch` +- `hidetwitch` +- `showonlymods` +- `showonlyvips` +- `showonlydonos` +- `showonlymembers` +- `filterevents` +- `hideallevents` + +The full list is in `parameters.md`. Treat it as the current parameter catalog. + +## API Actions + +`api.md` documents dock actions including: + +- `clear` +- `clearAll` +- `clearOverlay` +- `nextInQueue` +- `getQueueSize` +- `autoShow` +- `content` +- `feature` +- `toggleTTS` +- `tts` + +Example: + +```text +https://io.socialstream.ninja/SESSION_ID/nextInQueue +``` + +When controlling a specific dock, use a label: + +```text +dock.html?session=SESSION_ID&label=control +https://io.socialstream.ninja/SESSION_ID/nextInQueue/control/null +``` + +## External Output + +Dock can publish selected/featured messages to external systems through URL parameters: + +- `postserver` +- `putserver` +- `h2rurl` +- `h2r` +- `spxserver` +- `spxfunction` +- `spxlayer` +- `singular` + +These are normally added to the dock URL, because the dock is where selected/featured message actions happen. + +## TTS In The Dock + +Dock loads `tts.js` and can read incoming messages when TTS is enabled. Basic parameters: + +- `speech` / `tts` +- `volume` +- `rate` +- `pitch` +- `voice` +- `ttscommand` +- `ttscommandmembersonly` +- `simpletts` +- `readevents` +- `readouturls` + +Disabling TTS from the dock stops playback and clears the TTS queue. + +## OBS Usage + +Use `dock.html` as an OBS custom dock only for operator UI. For visible stream output, prefer `featured.html` or a purpose-built overlay page. + +OBS-specific notes: -- `social_stream/dock.html` -- `social_stream/api.md` -- `social_stream/parameters.md` -- `social_stream/docs/customoverlays.md` -- `stevesbot/resources/instructions/social-stream-support.md` +- Browser Source size of `1280x600` or `1920x600` is commonly recommended for chat overlay layouts. +- Use OBS Browser Source custom CSS for quick styling changes. +- On macOS/Linux, locally hosted dock/featured files may not behave well in OBS; hosted pages or OBS CSS are safer. +- OBS remote scene control requires an SSN page running as an OBS Browser Source with appropriate permissions, not just as a custom dock. -## Starter Notes +## Common Support Issues -Support guidance says a blank or white `dock.html` can be expected if the user does not understand it is a dashboard. It needs a matching `?session=` value to receive traffic. +| Symptom | Likely Cause | First Checks | +| --- | --- | --- | +| Empty dock | No source messages, wrong session, extension/app disabled | Session match, extension green/enabled, source page loaded. | +| Dock works but featured overlay does not | Overlay session mismatch or overlay not open | Open `featured.html?session=...`; click a dock message. | +| API commands do nothing | API toggle off or wrong channel/session | Enable remote API control; test `clearOverlay`. | +| Multiple docks all respond | Missing/incorrect `label` targeting | Add unique `&label=` to each dock. | +| Queue button missing | No queued items or mode hides controls | Check CTRL/cmd click, `viewonly`, `chatmode`, `helpermode`. | +| Auto-show feels delayed/skippy | Auto-show queue/filter behavior | Check `autoshowtime`, filters, donation/member modes. | +| TTS silent | Browser audio gate or system TTS routing | Click page, check provider, check OBS audio capture path. | +| Custom behavior not loading | Hosted page cannot load local custom file | Use local/forked dock or URL/script method. | -## Planned Sections +## Follow-Up Extraction Needs -- Required URL parameters -- Dashboard vs overlay behavior -- Manual featuring and autoshow -- Queue/pin/sync behavior -- TTS and OBS controls -- API actions -- Common support issues +- Line-level trace of `processInput` for every dock API action. +- Full dock URL parameter behavior matrix. +- Exact storage/export behavior for dock database/history features. +- User-facing screenshots/labels for toolbar buttons. diff --git a/docs/agents/07-overlays-and-pages/featured.md b/docs/agents/07-overlays-and-pages/featured.md index d9e4e02cb..edf7f01e3 100644 --- a/docs/agents/07-overlays-and-pages/featured.md +++ b/docs/agents/07-overlays-and-pages/featured.md @@ -1,28 +1,231 @@ # Featured Overlay -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started from `featured.html`, `api.md`, `parameters.md`, README, and featured-style theme docs. -## Purpose +## Source Anchors -Document `featured.html`, the overlay that displays selected or auto-selected chat messages. +- `featured.html` +- `samplefeatured.html` +- `api.md` +- `parameters.md` +- `README.md` +- `tts.js` +- `themes/featured-styles/README.md` +- `themes/featured-styles/*.html` -## Source Anchors +## Role + +`featured.html` is the main selected-message overlay. It shows the message chosen from `dock.html`, auto-show rules, or API commands. It is usually loaded as an OBS Browser Source and may look blank or transparent until a message is featured. + +Typical URL: + +```text +https://socialstream.ninja/featured.html?session=SESSION_ID +``` + +Support note: a blank page is normal when no message is currently featured, especially with transparent styling. + +## Basic Workflow + +1. Start the extension/app/source. +2. Open `dock.html?session=SESSION_ID`. +3. Open `featured.html?session=SESSION_ID` in OBS or a browser. +4. Click a message in the dock or enable auto-show. +5. Use the clear button or `showtime` to remove the featured message. + +If clicking a dock message does nothing, verify session ID match before debugging CSS. + +## Connection And Server Parameters + +`api.md` documents several server connection modes: + +| Parameter | Use | +| --- | --- | +| `server` | Connects featured page to the API server path. | +| `server2` | Alternate server routing mode. | +| `server3` | Alternate server routing mode for extension/server routing. | +| `password` | Session password when configured. | +| `lanonly` | Restricts peer routing to LAN-only behavior where supported. | +| `label` | Names the featured instance for targeted commands. | + +For normal users, a plain `session` URL is the first thing to test. Add server/label parameters only when the workflow requires them. + +## Display Timing And Animation + +Common parameters: + +| Parameter | Meaning | +| --- | --- | +| `showtime` | Auto-hides the message after the given number of milliseconds. | +| `fadein` / `fadeout` | Enables fade effects. | +| `swipeleft`, `swiperight`, `swipeup` | Slide-in direction variants. | +| `animatein`, `animateout` | Uses named animation styles. | +| `typewriter` | Types message text letter by letter. | +| `queuetime` | Queues featured messages and displays them sequentially. | +| `center` | README mentions centered featured messages for the featured overlay. | + +Example: + +```text +featured.html?session=SESSION_ID&showtime=20000&fadein +``` + +## Filtering + +Documented featured filters include: + +- `onlyshowdonos` +- `hideDonations` +- `hideevents` +- `filterevents` +- `hideTwitch` +- `onlyTwitch` +- `onlyFrom` +- `hideFrom` +- `filterfeaturedusers` + +Use these when one featured overlay should show only donations, one platform, approved users, or selected event types. + +## Message Payload + +Minimum payload: + +```json +{ + "chatname": "Username", + "chatmessage": "Message content", + "type": "external" +} +``` + +Common display fields: + +- `chatimg` +- `chatbadges` +- `contentimg` +- `hasDonation` +- `membership` +- `title` +- `subtitle` +- `sourceImg` +- `sourceName` +- `nameColor` +- `textColor` +- `backgroundColor` +- `event` +- `meta` + +Use `docs/agents/05-message-flow-and-event-contracts.md` and `api.md` for the full contract. + +## API Actions + +`api.md` documents these featured actions: + +| Action | Purpose | +| --- | --- | +| `content` | Display a new featured content object. | +| `clear` | Clear the current featured message. | +| `toggleTTS` | Toggle TTS. | +| `tts` | Set or toggle TTS state. | + +Example WebSocket payload: + +```json +{ + "action": "content", + "value": { + "chatname": "ExampleUser", + "chatmessage": "Hello, featured chat!", + "type": "twitch" + } +} +``` + +Example HTTP clear: + +```text +https://io.socialstream.ninja/SESSION_ID/clearOverlay +``` + +## TTS + +`featured.html` loads `tts.js`. TTS can be enabled with: + +```text +featured.html?session=SESSION_ID&speech=en-US +``` + +Common TTS parameters: + +- `speech` / `tts` +- `volume` +- `rate` +- `pitch` +- `voice` +- provider keys/settings from `parameters.md` + +OBS note: provider/browser TTS can usually be captured with OBS Browser Source audio. Free system Web Speech TTS may play through the OS output and require virtual cable/application/desktop audio capture. + +## Styling + +Fast styling options: + +- URL parameters from `parameters.md`. +- OBS Browser Source custom CSS field. +- `css` or `cssb64` URL parameters. +- Fork/local copy for code-level changes. +- `themes/featured-styles/*.html` for prebuilt modern/animated/3D/particle styles. + +Theme docs list examples: + +```text +featured-modern.html?session=SESSION_ID&style=glass +featured-animated.html?session=SESSION_ID&style=bounce +featured-3d.html?session=SESSION_ID&style=cube +featured-particles.html?session=SESSION_ID&style=matrix +``` + +Featured-style theme parameters include: + +- `session` / `room` +- `style` +- `password` +- `showtime` +- `server` +- `exit` +- `tts` +- `voice` +- `pitch` +- `rate` + +## OBS Setup + +Common setup: + +1. Add an OBS Browser Source. +2. Paste the `featured.html?session=...` URL. +3. Use a size such as `1280x600`, `1920x600`, or full canvas for themed overlays. +4. Enable browser-source audio control when using browser/provider TTS. +5. Refresh the source after URL or CSS changes. -- `social_stream/featured.html` -- `social_stream/api.md` -- `social_stream/parameters.md` -- `social_stream/docs/customoverlays.md` -- `social_stream/themes/featured-styles/**` +For full-canvas themed overlays, `1920x1080` is commonly suggested by the theme docs. -## Starter Notes +## Common Support Issues -Support history says users can confuse a white or empty browser view with a broken overlay. The featured page often has transparent background behavior intended for OBS. +| Symptom | Likely Cause | First Checks | +| --- | --- | --- | +| Blank overlay | No featured message yet | Click a dock message or send API `content`. | +| White browser page | Viewing a transparent/empty overlay outside OBS | Test after featuring a message; check CSS/background. | +| Dock has messages but overlay does not | Wrong session or stale OBS source | Match session ID; refresh OBS Browser Source. | +| Message appears then vanishes | `showtime` or clear action | Remove/raise `showtime`; check automation/API. | +| All overlays respond | Missing `label` targeting | Add `&label=` and target API commands. | +| TTS silent | Browser audio gate or provider issue | Click page in browser, check OBS audio control, test provider. | +| Local custom CSS/page fails on macOS/Linux OBS | Local-file behavior limitation | Use hosted page or OBS Browser Source CSS. | +| Wrong style/font | CSS precedence | Add `!important`, check loaded CSS URL/base64 value. | -## Planned Sections +## Follow-Up Extraction Needs -- Connection methods -- Manual vs autoshow -- Styling and themes -- OBS browser source setup -- API actions -- Troubleshooting blank/transparent output +- Full parameter matrix specific to `featured.html`. +- Line-level trace of queue/timeouts and TTS lifecycle. +- Current compatibility matrix for every `themes/featured-styles` overlay. +- Rendered examples/screenshots for blank/transparent troubleshooting. diff --git a/docs/agents/07-overlays-and-pages/index.md b/docs/agents/07-overlays-and-pages/index.md index 75144dbd9..06c6b2912 100644 --- a/docs/agents/07-overlays-and-pages/index.md +++ b/docs/agents/07-overlays-and-pages/index.md @@ -1,6 +1,6 @@ # Overlays And Pages Index -Status: framework only. Detailed extraction not started. +Status: framework plus heavy passes for dock, featured, multi-alerts, waitlist/polls/games, and custom overlays. ## Purpose @@ -8,11 +8,11 @@ This section covers SSN pages users open in browsers, OBS, the extension, or the ## Pages -- `dock.md` -- `featured.md` -- `multi-alerts.md` -- `waitlist-polls-games.md` -- `custom-overlays.md` +- `dock.md`: heavy extraction pass started. +- `featured.md`: heavy extraction pass started. +- `multi-alerts.md`: heavy extraction pass started. +- `waitlist-polls-games.md`: heavy extraction pass started. +- `custom-overlays.md`: heavy extraction pass started. ## Source Anchors @@ -22,3 +22,10 @@ This section covers SSN pages users open in browsers, OBS, the extension, or the - `social_stream/api.md` - `social_stream/parameters.md` - `social_stream/themes/**` + +## Suggested Next Pass + +- Intense pass for `dock.md` and `featured.md` by tracing exact API actions and URL parameters in code. +- Intense pass for `multi-alerts.md` using the Playwright E2E script and per-platform event payload examples. +- Intense pass for `waitlist-polls-games.md` by extracting each `games/*.html`, `battle.html`, and current background command handlers. +- Intense pass for `custom-overlays.md` by producing a safe minimal overlay template and compatibility table. diff --git a/docs/agents/07-overlays-and-pages/multi-alerts.md b/docs/agents/07-overlays-and-pages/multi-alerts.md index b0080487f..11de4b779 100644 --- a/docs/agents/07-overlays-and-pages/multi-alerts.md +++ b/docs/agents/07-overlays-and-pages/multi-alerts.md @@ -1,10 +1,10 @@ # Multi Alerts -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started on 2026-06-24. ## Purpose -Document the multi-alerts page and how alert-like events are routed and displayed separately from normal chat. +`multi-alerts.html` is an alert overlay for event-style SSN payloads. It is separate from normal chat overlays and focuses on follows, subscriptions, donations, cheers/bits, raids, auction wins, and hype-train events. ## Source Anchors @@ -12,15 +12,231 @@ Document the multi-alerts page and how alert-like events are routed and displaye - `social_stream/multi-alerts.js` - `social_stream/popup.html` - `social_stream/docs/event-reference.html` +- `social_stream/scripts/playwright-multi-alerts-overlay-e2e.cjs` -## Starter Notes +## Connection Model -Alert-style events may include follows, subs, raids, donations, memberships, or other platform events. Some settings can route events away from `dock.html` and into alert overlays. +The page can receive payloads in two ways: -## Planned Sections +- Hidden VDO.Ninja iframe bridge, using the SSN session and `label=alerts`. +- WebSocket mode when `server`, `server2`, `server3`, or `localserver` URL parameters are present. -- Event types consumed -- Setup and URL parameters -- Interaction with popup settings -- Styling and layout -- Common failures +Iframe URL pattern in source: + +```text +https://vdo.socialstream.ninja/?ln&salt=vdo.ninja&password=PASSWORD&push&label=alerts&view=SESSION&vd=0&ad=0&novideo&noaudio&autostart&cleanoutput&room=SESSION +``` + +Socket join pattern: + +```json +{ "join": "SESSION", "out": 3, "in": 4 } +``` + +The page also accepts local preview messages through `window.postMessage` with `multiAlertsPreview`. + +## Alert Categories + +Current alert categories: + +- `follow` +- `subscription` +- `donation` +- `bits` +- `raid` +- `auction` +- `hype` + +The default user-facing labels are: + +- New Follower +- New Subscriber +- New Donation +- New Cheer +- Incoming Raid +- Auction Won +- Hype Train + +## Event Classification + +The page normalizes many platform event names into alert categories. + +Examples: + +- Follow: `new_follower`, `follow`, `followed`. +- Subscription: `new_subscriber`, `subscription_gift`, `resub`, `sponsorship`, `giftpurchase`, `giftredemption`, `membermilestone`, plus older aliases such as `subscription`, `membership`, `new_member`, and `membership_upgrade`. +- Donation/gift: `donation`, `gift`, `gift_sent`, `gift_message`, `live_gift`, `tiktok_gift`, `supersticker`, `tip`, `support`, and related aliases. +- Bits: `cheer`, `bits`. +- Raid: `raid`, `host`, `hosting`, `redirect`. +- Auction: `auction_update`. +- Hype train: `hype_train`. + +Count/status events such as `viewer_update`, `viewer_updates`, `follower_update`, `subscriber_update`, `stream_status`, and ad-break events are not treated as normal alert cards. + +## Important Payload Fields + +The alert card builder looks at many common SSN fields: + +- `event` +- `eventType` +- `alertType` +- `chatname` +- `chatmessage` +- `chatimg` +- `contentimg` +- `hasDonation` +- `donation` +- `membership` +- `id` +- `type` +- `sourceName` +- `channel` +- `channelId` +- `meta` + +For donations and bits, it tries to parse a cash-like value from labels and numeric fields such as: + +- `donoValue` +- `donationValue` +- `meta.donoValue` +- `meta.donationValue` +- `meta.amount` + +If `mindonation` or `mincash` is set, donation/bits alerts below that parsed value are skipped. + +## URL Parameters + +Core: + +- `session`: SSN session ID. +- `password`: session password, defaulting to `false`. +- `server`: use the API WebSocket endpoint, defaulting to `wss://io.socialstream.ninja/api`. +- `server2` or `server3`: use extension WebSocket endpoint, defaulting to `wss://io.socialstream.ninja/extension`. +- `localserver`: use `ws://127.0.0.1:3000`. +- `debug`: log extra diagnostics and show status. +- `preview`: preview-only mode. +- `showstatus`: show the status chip. + +Timing and queue: + +- `showtime`: alert display time, minimum clamped to 1800 ms, default 8000 ms. +- `cooldown`: delay between alerts, default 900 ms. +- `queue`: enable queueing. +- `noqueue`: force no queueing. +- `maxqueue`: queue cap, clamped 1 to 100, default 20. +- `minshowtime`: lower bound when queue pressure shortens alert display, default 3000 ms. + +Category styles: + +- `followstyle` +- `substyle` +- `donostyle` +- `bitsstyle` +- `raidstyle` +- `auctionstyle` +- `hypestyle` + +Default style is `twitch`. HTML/CSS also defines `classic`, `twitch`, and `minimal` themes. + +Category disable/enable: + +- `disablefollows` +- `disablesubs` +- `disabledonos` +- `disablebits` +- `disableraids` +- `auctionwins`: opt in to auction alerts. +- `hypetrain`: opt in to hype-train alerts. + +Category sounds: + +- `followsound` +- `subsound` +- `donosound` +- `bitssound` +- `raidsound` +- `auctionsound` +- `hypesound` + +General audio: + +- `beep` +- `beepvolume` +- `custombeep` + +Layout/display: + +- `compact` +- `hideavatar` +- `hidemedia` +- `hidesource` +- `hideamount` +- `hidesubtitle` +- `align=center` +- `alignright` +- `scale` +- `mediascale` +- `headlinescale` +- `detailscale` +- `pagebg` +- `chroma` +- `transparent` or `transparency` +- `embedded` + +Source filters: + +- `sources`: include only specific source types. +- `hidesources`: exclude source types. +- `sourceids` or `channels`: include matching channel/source IDs. +- `hidesourceids` or `hidechannels`: exclude matching channel/source IDs. + +## Queue Behavior + +Without `queue`, a new alert can replace or interrupt the current display depending on timing. With `queue`, models are stored and played sequentially. The queue is trimmed to `maxqueue`. + +When the queue is deep, source shortens effective show/cooldown timing to keep alerts moving. + +## Audio Unlock Behavior + +Browsers can block autoplay audio. The page registers pointer, mouse, touch, key, and click listeners to unlock audio. If alert sounds do not play, the user may need to click/interact with the overlay once, especially in a normal browser tab. + +In OBS Browser Source, audio routing and browser-source audio settings can also be the cause. + +## Common Failures + +No alerts: + +- `session` is missing or wrong. +- The page is connected to `label=alerts`, but SSN is not sending alert payloads for that session. +- The event is a normal chat message and does not classify as an alert. +- Category is disabled by URL parameter. +- Auction/hype is not enabled with `auctionwins` or `hypetrain`. +- Source is excluded by `sources`, `hidesources`, `sourceids`, or `hidesourceids`. + +Donation alert missing: + +- `mindonation` / `mincash` may be filtering it. +- Source payload may not include `hasDonation`, `donation`, or a numeric value field. +- Gift payloads can classify as donation/gift depending on event alias. + +Audio missing: + +- Browser autoplay lock. +- Bad sound URL. +- OBS Browser Source audio disabled or not monitored. +- `beep`/category sound parameter not set. + +Wrong style/layout: + +- Category style parameters are per category. Setting `donostyle` does not affect follows. +- `compact`, scale, and media scale parameters can make cards look very different from default. + +Repeated alerts: + +- The page has duplicate payload protection, but source IDs or event IDs matter. If the upstream source emits the same event with changing IDs, duplicates may still appear. + +## Remaining Extraction Targets + +- Trace popup-generated multi-alert URLs and settings labels. +- Run/inspect the Playwright multi-alerts E2E script for expected render behavior. +- Map each platform's current event names into the category classifier. diff --git a/docs/agents/07-overlays-and-pages/waitlist-polls-games.md b/docs/agents/07-overlays-and-pages/waitlist-polls-games.md index 6c22aba7f..50631aa92 100644 --- a/docs/agents/07-overlays-and-pages/waitlist-polls-games.md +++ b/docs/agents/07-overlays-and-pages/waitlist-polls-games.md @@ -1,10 +1,10 @@ # Waitlist Polls And Games -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started on 2026-06-24. ## Purpose -Document pages that turn chat into interactive workflows: waitlists, polls, timers, giveaways, games, battles, scores, and related tools. +This page documents SSN's interactive browser/OBS tools: waitlists, polls, timers, giveaways, and chat-driven games. These tools consume SSN session traffic but often maintain their own state and command surfaces. ## Source Anchors @@ -12,19 +12,359 @@ Document pages that turn chat into interactive workflows: waitlists, polls, time - `social_stream/poll.html` - `social_stream/timer.html` - `social_stream/giveaway.html` -- `social_stream/battle.html` +- `social_stream/giveaway-obs-entries.html` +- `social_stream/games.html` - `social_stream/games/**` - `social_stream/api.md` -## Starter Notes +## Shared Setup Pattern -These pages are feature-specific consumers of the same session/message system. API docs already include some controls for waitlist, poll, timer, and battle behavior. +Most pages require: -## Planned Sections +- `session`: SSN session ID. +- `password`: optional session password, defaulting to `false`. +- A hidden VDO.Ninja iframe bridge. -- Page inventory -- Setup requirements -- Chat commands or triggers -- API controls -- OBS usage -- Support issues +Many tools also support WebSocket/API mode with: + +- `server` +- `server2` +- `server3` +- `localserver` + +Do not assume every tool uses the same channels. Each page defines its own join channel pair and label. + +## Waitlist + +Page: + +```text +waitlist.html +``` + +Connection: + +- Reads `session`, `s`, or `id`. +- If opened as a local file without a session, it prompts for one. +- Hidden iframe uses `label=waitlist`. +- Optional WebSocket path joins with `out: 5`, `in: 6`. + +Important URL parameters: + +- `password` +- `drawmode` +- `includemessage` +- `messagesize` +- `randomize` or `random` +- `showsource` +- `hidetitle` +- `css` +- `base64css`, `b64css`, `cssbase64`, or `cssb64` +- `font` +- `scale` +- `alignright` +- `aligncenter` +- `showtime` +- `sound` +- `pagebg`, `pagebackground`, or `dockbg` + +Incoming payload keys it handles: + +- `waitlistmessage`: updates the title. +- `remove`: updates title/remove display state. +- `drawmode`: switches draw display behavior. +- `winlist`: winner list. +- `drawPoolSize`: current number of entries in the draw pool. +- `waitlist`: full waitlist array or `false`. + +Waitlist entries can include: + +- `chatname` +- `chatmessage` +- `waitlistJoinMessage` +- `waitlistTrigger` +- `type` +- `waitStatus` +- `randomStatus` + +Common API actions documented in `api.md`: + +- `removefromwaitlist` +- `highlightwaitlist` +- `resetwaitlist` +- `stopentries` +- `downloadwaitlist` +- `selectwinner` +- `drawmode` +- `waitlistmessage` + +Support notes: + +- If the waitlist page is blank, confirm the URL has the right session and the waitlist is actually receiving `waitlist` or draw payloads. +- `drawmode` changes display semantics. It can show only pool counts or winners rather than a normal queue. +- `showsource` depends on platform icon files under `sources/images`. + +## Poll + +Page: + +```text +poll.html +``` + +Connection: + +- Hidden iframe uses `label=poll`. +- `server` mode joins `out: 2`, `in: 1`. +- `server2` / `server3` extension mode joins `out: 3`, `in: 4`. + +Core URL parameters: + +- `session` +- `password` +- `pollType`: `freeform`, `multiple`, or `yesno`. +- `pollQuestion` +- `pollOptions`: comma-separated options. +- `pollMatchMode`: current code supports exact behavior and `hashtag-anywhere`. +- `pollTimer` +- `pollEnabled` +- `style` +- `pollSpam` +- `pollTally` +- `pollDonationWeighted` +- `debug` + +Poll behavior: + +- `yesno` sets options to `Yes` and `No`. +- `multiple` accepts numeric votes and text votes matching configured options. +- `freeform` accepts hashtags and numeric selection when options exist. +- `hashtag-anywhere` lets `#word` appear anywhere in the message. +- Votes are keyed by user ID when available, otherwise by name plus source. +- If `pollSpam` is off, duplicate voters are ignored. +- If `pollDonationWeighted` is on, donation amount can increase vote weight. +- UI updates are throttled to reduce DOM churn. + +Commands accepted by the page: + +- `startpoll` +- `resetpoll` +- `closepoll` + +`api.md` also documents higher-level poll actions handled elsewhere: + +- `loadpoll` +- `getpollpresets` +- `setpollsettings` +- `createpoll` + +Support notes: + +- If votes do not count, confirm `pollEnabled` is true and the poll is not closed. +- For multiple choice polls, users can vote by number or matching option text. +- For freeform polls, users generally vote with hashtags. +- Duplicate prevention can make testing look broken when the same name/user votes repeatedly. + +## Timer + +Page: + +```text +timer.html +``` + +Connection: + +- Hidden iframe uses `label=timer`. +- Optional `server` mode joins `out: 2`, `in: 1`. +- It can register with the extension by sending `registerTimer` once it sees the `SocialStream` peer. + +Core URL parameters: + +- `session` +- `password` +- `operator` or `controls`: show local controls and register as operator. +- `mode`: `countdown` or `countup`. +- `countup`: shorthand for count-up mode. +- `duration` +- `current` +- `label` +- `style`: `stage`, `compact`, or `ring`. +- `autostart` +- `warn` +- `danger` +- `sound` +- `customsound` +- `css` +- `base64css`, `b64css`, `cssbase64`, or `cssb64` +- `scale` +- `server` +- `localserver` + +Commands accepted: + +- `starttimer` +- `pausetimer` +- `toggletimer` +- `resettimer` +- `timeradd` +- `timersubtract` +- `settimer` +- `gettimerstate` + +`settimer` accepts values such as: + +- `seconds` +- `duration` +- `current` +- `currentSeconds` +- `label` +- `mode` +- `style` +- `warn` +- `warnSeconds` +- `danger` +- `dangerSeconds` +- `sound` +- `customsound` +- `soundUrl` +- `autostart` +- `running` + +`gettimerstate` responds on the WebSocket with a callback result containing current timer state. + +Support notes: + +- Timer sound can require a user gesture before browsers allow playback. +- `operator`/`controls` affects whether the control panel is shown and whether the page registers itself as an operator. +- If remote commands fail, check whether the page is connected by iframe, API WebSocket, or only local controls. + +## Giveaway + +Pages: + +```text +giveaway.html +giveaway-obs-entries.html +``` + +`giveaway.html` is the controller and entrant wheel. `giveaway-obs-entries.html` is the OBS companion view for wheel/winner display. + +Connection: + +- Reads `session`, `s`, or `id`. +- Hidden iframe uses `label=dock` because it consumes ordinary chat messages as entries. +- WebSocket mode joins `out: 5`, `in: 6`. +- Local communication uses `BroadcastChannel` when available, with localStorage fallback. + +State: + +- Entrants are stored in memory and persisted to `localStorage` as `giveawayWheelState`. +- Keyword is persisted as `giveaway_keyword`. +- Winners are persisted as `giveaway_winners`. +- Settings are persisted as `giveaway_settings`. + +Entry behavior: + +- Default keyword is `ENTER`. +- When exact match is disabled, any chat message containing the keyword can enter. +- When exact match is enabled, the keyword must match as a bounded word pattern. +- Entrant IDs are based on name plus platform, so the same user/platform only enters once. +- UI and broadcast updates are batched for high-rate chat. + +Actions/broadcast messages: + +- `giveaway_update` +- `entrants_update` +- `entrant_remove` +- `keyword_update` +- `spin_update` +- `winner_update` +- `style_update` +- `giveaway_state_request` + +Support notes: + +- If the OBS entries view does not update, confirm both pages use the same session and password. +- If entrants are not added, confirm the keyword and exact-match setting. +- If old entrants reappear, clear saved localStorage state or use the page controls to clear/reset. +- If high-volume chat lags, the page intentionally batches UI/broadcast saves. + +## Games + +Main page: + +```text +games.html +``` + +Game files also exist under: + +```text +games/ +``` + +The inspected `games.html` implements a chat activity game called Spam Power. + +Connection: + +- Reads `session` or `room`, defaulting to `test`. +- Reads `password`. +- `lanonly` is passed into the iframe URL when present. +- Hidden iframe uses `label=dock`. +- `server` mode joins `out: 2`, `in: 1`. +- `server2` / `server3` extension mode joins `out: 3`, `in: 4`. + +Display parameters: + +- `chroma` +- `darkmode` +- `demo` + +Behavior: + +- Counts incoming SSN messages that include both `chatmessage` and `chatname`. +- Tracks messages per second. +- Applies multipliers at 5+ and 10+ messages per second. +- Maintains historical stats in localStorage: peak activity, wins, best streak, average win rate, and recent goals. +- `demo` injects sample chat messages for testing the game without a live source. + +Support notes: + +- If the game does not react, confirm it is receiving ordinary chat payloads on `label=dock`. +- If it seems too hard/easy, localStorage history influences dynamic goals. +- `demo` is useful to distinguish connection issues from rendering/game logic. + +## Common Troubleshooting Across Tools + +Tool page is blank: + +- Check `session`. +- Check `password`. +- Confirm the relevant SSN feature is sending payloads for that tool. +- Open browser dev tools for JavaScript errors. + +Remote/API control does not work: + +- Confirm the relevant API toggles are enabled in SSN settings. +- Confirm the page is connected to the expected WebSocket server and channel pair. +- Use the exact action names; these pages generally lower-case commands. + +OBS view does not update: + +- Confirm OBS Browser Source URL has the same session/password. +- Confirm browser-source cache is not showing an old URL. +- For giveaway, confirm controller and OBS entries page are connected through the same local/session transport. + +Audio does not play: + +- Browser autoplay policy may require a click or keypress. +- Check OBS Browser Source audio settings. +- Confirm custom sound URL is reachable. + +## Remaining Extraction Targets + +- Extract each `games/*.html` file into a per-game matrix. +- Source-check `battle.html` and any score/battle pages not present in this pass. +- Trace popup-generated URLs for waitlist, poll, timer, and giveaway. +- Cross-check `api.md` command descriptions against current background command handlers. diff --git a/docs/agents/08-platform-sources/discord.md b/docs/agents/08-platform-sources/discord.md index aefc22649..0cab5cf92 100644 --- a/docs/agents/08-platform-sources/discord.md +++ b/docs/agents/08-platform-sources/discord.md @@ -1,10 +1,10 @@ # Discord Source -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started on 2026-06-24. ## Purpose -Document Discord source behavior and how it differs from Discord support-data sources in `stevesbot`. +Document Discord as an SSN platform source. This is separate from Discord support-history mining in `stevesbot`; that support archive is a data source for documentation, not the same thing as SSN's Discord capture script. ## Source Anchors @@ -12,14 +12,126 @@ Document Discord source behavior and how it differs from Discord support-data so - `social_stream/docs/event-reference.html` - `stevesbot/data/sqlite/archive.sqlite` -## Starter Notes +## Capture Model -Discord appears both as an SSN source and as the historical support data origin. Keep those separate: Discord source docs should describe SSN capture behavior, while support KB docs should describe mined support history. +`sources/discord.js` is a DOM-based content script for Discord web pages. It watches the message list under: -## Planned Sections +```text +[data-list-id="chat-messages"] +``` -- Discord as platform source -- Message fields -- Attachments/media -- Common source failures -- Difference from support archive data +It only runs message capture on URLs containing: + +```text +/channels/ +``` + +New Discord message rows are processed through a `MutationObserver`. + +## Enablement Rules + +The script checks: + +- `settings.discord`, unless running inside SSApp/Electron-like contexts (`window.ninjafy` or `window.electronApi`). +- Optional custom channel restrictions from `settings.customdiscordchannel.textsetting`. + +If custom Discord channels are configured, the current URL's final path segment must match one of the configured values. This can be used to limit capture to specific channels. + +## Message Extraction + +For each Discord row, the script extracts: + +- Message ID into `id`. +- Username from `#message-username-*`. +- Avatar URL from Discord avatar images. +- Name color from the username node. +- Bot marker from bot tag selectors. +- Message body from `#message-content-*`. +- Embed description fallback from `#message-accessories-*`. +- Attached image/video/sticker/canvas media into `contentimg`. + +If a message row omits the username/avatar because Discord visually groups consecutive messages, the script walks backward through previous rows to find the prior username/avatar. + +Rows where the inferred name contains ` @ ` are treated as likely relayed webhook messages and skipped. + +## Payload Fields + +Discord payloads include: + +- `id` +- `chatname` +- `chatbadges` +- `backgroundColor` +- `textColor` +- `bot` +- `event` +- `chatmessage` +- `chatimg` +- `nameColor` +- `hasDonation: ""` +- `membership` +- `contentimg` +- `textonly` +- `type: "discord"` + +If no name is found, `event` is set to `true`. + +If a name color exists and `settings.discordmemberships` is enabled, `membership` is set to the localized membership label. + +The script converts `contentimg` and `chatimg` to data URLs where possible before relaying. + +## UI Helper Behavior + +The script includes a keyboard helper: + +- `Ctrl+Shift+<` hides most page elements except video/overlay title elements. +- `Ctrl+Shift+>` restores them. + +This appears intended for cleaning up a Discord view when used as a visual source. + +The source also listens for `focusChat` messages and focuses Discord's text area when the active channel is allowed. + +## Common Failures + +No Discord messages: + +- Confirm the Discord setting is enabled, unless using SSApp/Electron where the script bypasses that specific setting check. +- Confirm the page URL includes `/channels/`. +- Confirm the channel is allowed by `customdiscordchannel` if configured. +- Confirm the Discord web page is open and showing new messages. +- Discord DOM class/name changes can break selectors. + +Attachments missing: + +- The script searches normal images, video posters, sticker images, and sticker canvas. Other attachment layouts may not be captured. +- Some media conversion to data URL can fail due to browser/CORS behavior. + +Bot messages missing: + +- Bots are marked with `bot: true`, not automatically blocked by this script. +- A relayed webhook-style name containing ` @ ` is skipped to avoid echo loops. + +Membership missing: + +- `settings.discordmemberships` must be enabled. +- Discord must expose a usable name color. +- This is a heuristic membership marker, not a full Discord role API lookup. + +Duplicate messages: + +- The script keeps a `lastMessage` serialized payload check and a highest message ID tracker, but DOM rerenders can still create edge cases. + +## Support Boundary + +When mining Discord support data from `stevesbot`, keep these concepts separate: + +- Discord as an SSN source: this page and `sources/discord.js`. +- Discord as historical support archive: user conversations and bot support logs stored in SQLite or exported files. + +Do not cite support archive data as if it were Discord source behavior unless the current source code confirms the behavior. + +## Remaining Extraction Targets + +- Source-check popup/source setup labels for Discord. +- Verify current Discord setting names in `settings/*` and `popup.js`. +- Mine support history for current Discord-specific capture failures and validate against this source. diff --git a/docs/agents/08-platform-sources/facebook.md b/docs/agents/08-platform-sources/facebook.md index e3f6e7010..14b74f94f 100644 --- a/docs/agents/08-platform-sources/facebook.md +++ b/docs/agents/08-platform-sources/facebook.md @@ -1,10 +1,10 @@ # Facebook Source -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started on 2026-06-24. ## Purpose -Document Facebook capture behavior, login requirements, app OAuth helper, and support issues. +Document SSN's Facebook capture paths: DOM capture on Facebook/Workplace pages and the managed Page Graph API bridge. ## Source Anchors @@ -14,14 +14,174 @@ Document Facebook capture behavior, login requirements, app OAuth helper, and su - `ssapp/resources/electron-facebook-handler.js` - `stevesbot/resources/instructions/social-stream-support.md` -## Starter Notes +## Capture Modes -Existing support guidance says Facebook may need viewer mode rather than publisher mode, and network/device context can matter. +### DOM Capture -## Planned Sections +`sources/facebook.js` is a Chrome extension content script. It watches Facebook live/chat DOM rows and extracts visible messages. -- Standard capture setup -- WebSocket source behavior -- Login/OAuth in app -- Viewer vs publisher mode -- Common failures +It can emit: + +- `type: "facebook"` for Facebook. +- `type: "workplace"` when the URL is Workplace. +- `chatname` +- `chatmessage` +- `chatimg` +- `chatbadges` +- `contentimg` +- `hasDonation` for Stars data +- `donoValue` for parsed Stars amount +- `highlightColor` for highlighted messages +- `initial` and `reply` when reply context is included +- `textonly` + +It has duplicate protection for recent rows and special handling for Stars row IDs. + +### Managed Page API Bridge + +`sources/websocket/facebook.html` and `sources/websocket/facebook.js` implement a Facebook Live comments bridge using the Facebook Graph API. + +The page is meant for Pages the user manages. The setup notes in the page say: + +1. This only works for Pages you manage. +2. Sign in, pick a Page, resolve the live video, then connect. +3. Manual fallback: paste a Page token and video ID yourself. +4. Auto-connect URL can include `videoId`, `access_token`, and `autoconnect=1`. + +The bridge polls live video comments and optionally viewer count. Keep the page open while it should relay Facebook Live comments into SSN. + +## API Bridge Setup + +Normal setup: + +1. Open the Facebook bridge page. +2. Click Sign in with Facebook. +3. Select a managed Page. +4. Resolve or enter the live video ID. +5. Click Connect. + +Manual setup: + +1. Paste a Page access token. +2. Paste a live video ID or Facebook video URL. +3. Optionally enter a Page ID/page name for resolve. +4. Connect. + +Advanced fields in the page: + +- `videoId` +- `pageId` +- `access_token` or `token` +- `poll` +- `autoconnect` +- `live_filter` +- `oauthBase` + +The default OAuth service URL in source is: + +```text +https://auth.socialstream.ninja/auth/facebook/pages +``` + +Support should not ask users to change that unless debugging a known auth-service issue. + +## API Bridge Payloads + +Comment payloads include: + +- `platform: "facebook"` +- `type: "facebook"` +- `chatname` +- `chatmessage` +- `chatimg` from Graph profile picture URL when a sender ID is available +- `chatbadges` +- `backgroundColor` +- `textColor` +- `hasDonation` +- `membership` +- `textonly` +- `timestamp` +- `meta` + +`meta` includes: + +- `commentId` +- `fromId` +- `fromName` +- `createdTime` +- `permalink` +- `videoId` +- `pageId` +- `attachment` when present + +Viewer-count payloads use: + +- `platform: "facebook"` +- `type: "facebook"` +- `event: "viewer_update"` +- `meta` set to the viewer value +- empty chat fields +- `textonly: true` + +## Polling And Errors + +The API bridge polls comments using Graph API fields: + +```text +id,from{name,id},message,created_time,permalink_url,attachment +``` + +If live filter is enabled, it requests `live_filter=stream`; otherwise it falls back to chronological ordering. If the API reports live filter is unsupported, the code switches to chronological polling. + +For invalid token or permission errors, especially Graph error codes `190` or `10`, the bridge stops and shows an access-token/permission error. + +Polling uses backoff after failures, up to a larger delay. + +## DOM Capture Notes + +DOM capture is useful when the user is watching a Facebook live page in a browser tab and the extension can read visible comments. It is more fragile than API polling because Facebook markup changes frequently. + +DOM capture includes reply context unless `excludeReplyingTo` is enabled. It can parse Stars information into `hasDonation` and `donoValue`. + +Existing support history says Facebook can depend on the viewing context. For end-user troubleshooting, ask whether the user is viewing the live as a normal viewer/Page admin and whether comments are visibly appearing in the opened source tab. + +## Common Failures + +API bridge cannot sign in: + +- Popup blocked by browser. +- Auth service unavailable. +- User does not manage any Pages. +- Browser/local storage has stale auth state; use Clear sign-in and sign in again. + +API bridge connects but no comments: + +- Wrong Page selected. +- Wrong live video ID. +- No active live comments yet. +- Live filter not supported; allow chronological fallback. +- Page token lacks needed permission or has expired. + +Viewer count missing: + +- Viewer-count polling may be disabled. +- The Graph API may return a different viewer field or no live viewer count for the video state. +- In extension use, the page notes viewer count can be controlled by SSN's `showviewercount` setting. + +DOM capture sees no messages: + +- The wrong Facebook surface is open. +- The page is in a publisher/admin mode that does not expose comments the same way as viewer mode. +- Facebook changed selectors. +- Extension capture is off or settings did not reach the content script. + +Stars/donations missing: + +- Confirm the Stars row is visible in the DOM for DOM capture. +- The API bridge comment payload extraction does not currently document Stars parsing the same way DOM capture does. + +## Remaining Extraction Targets + +- Read `ssapp/resources/electron-facebook-handler.js` line-by-line for standalone OAuth details. +- Cross-check current Graph API permission names and token lifetime expectations against Facebook's current official docs before publishing public auth instructions. +- Verify support-mined viewer-mode advice against current Facebook DOM capture behavior. diff --git a/docs/agents/08-platform-sources/generic-and-custom-sources.md b/docs/agents/08-platform-sources/generic-and-custom-sources.md index e1367b23f..870277cd9 100644 --- a/docs/agents/08-platform-sources/generic-and-custom-sources.md +++ b/docs/agents/08-platform-sources/generic-and-custom-sources.md @@ -1,30 +1,227 @@ # Generic And Custom Sources -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started from repo docs, source examples, and custom script templates. -## Purpose +## Source Anchors -Document generic source capture, custom source patterns, and how new sources should be added or debugged. +- `sources/generic.js` +- `sources/README.md` +- `sources/websocket/*.html` +- `sources/websocket/*.js` +- `sample_wss_source.html` +- `custom_sample.js` +- `custom_actions.js` +- `README.md` +- `docs/commands.html` +- `parameters.md` +- `manifest.json` -## Source Anchors +## What Counts As "Custom" In SSN + +SSN has several customization paths. They solve different problems and should not be described as one single plugin system. + +| Need | Recommended Path | Notes | +| --- | --- | --- | +| Change visual style | URL parameters or CSS | Best first step for overlay appearance. | +| Build a full custom visual surface | Custom overlay HTML | Use `sampleoverlay` or a fork/local HTML page. | +| Add custom dock/featured behavior | Local `custom.js` from `custom_sample.js` | Requires local/hosted page context that can load the file. | +| Filter/modify/respond to messages globally | Uploaded `custom_actions.js` style `window.customUserFunction` | Runs in the background processing path when enabled. | +| Send messages from an external source | API, WebSocket, or `sample_wss_source.html` pattern | Good for bots, tools, donation sources, and custom apps. | +| Add a first-class platform integration | New `sources/*.js` or `sources/websocket/*` files plus manifest/settings/docs | Developer workflow; see `12-development/adding-a-source.md`. | + +Use precise wording in support answers: SSN supports scriptable customization and plugin-like workflows, but a normal user should usually choose one of the paths above rather than look for a package manager or marketplace. + +## Generic DOM Capture + +`sources/generic.js` is a broad DOM-capture script. It tries to recognize common chat/message structures rather than targeting one platform's exact markup. + +Confirmed behavior from the current file: + +- It defines broad message selectors such as chat/message/comment row classes and common test IDs. +- It has helper logic to collect content nodes, preserve images when not in text-only mode, and avoid obvious timestamp/metadata elements. +- It deduplicates repeated username/message pairs over a short time window. +- It builds SSN-style message objects with fields such as `chatname`, `chatmessage`, `textonly`, and `type`. +- It sends captured messages through `chrome.runtime.sendMessage(chrome.runtime.id, { message: data }, ...)`. + +Use generic capture when: + +- A site has ordinary DOM chat and no special API/transport needs. +- The goal is quick proof-of-concept support. +- The source can tolerate imperfect selectors or needs a starting point for a proper source. + +Avoid relying on generic capture when: + +- The platform uses virtualized/shadow DOM that hides message data. +- Message identity/deletion/moderation sync matters. +- Events, gifts, donations, or membership metadata need normalized fields. +- The platform has a stable WebSocket/API path that gives cleaner data. + +## Local `custom.js` + +`custom_sample.js` documents a local `custom.js` path for dock/featured pages. + +Pattern: + +- Rename `custom_sample.js` to `custom.js`. +- Edit `applyCustomActions(data)` for dock behavior. +- Edit `applyCustomFeatureActions(data)` for featured overlay behavior. +- Open the local/hosted `dock.html` or `featured.html` that can load that custom file. + +Important limits: + +- The sample says this is not uploaded through the menu. +- The sample says it will not work from hosted `https://socialstream.ninja/dock.html` when expecting a local `custom.js`. +- The sample uses URL parameters such as `&auto1` to opt into behavior. +- Returning `null` from `applyCustomActions(data)` stops processing; returning the modified `data` continues. + +Good use cases: + +- Auto-response experiments. +- Local-only helper behavior. +- Stream-specific message tweaks. +- Testing a custom dock/featured behavior before building a full overlay. + +## Uploaded Custom User Function + +`custom_actions.js` is a template for a custom user function uploaded/enabled through SSN settings. + +Entry point: + +```javascript +window.customUserFunction = function(data) { + return data; +}; +``` + +Confirmed processing path: + +- `background.js` defines a default `window.customUserFunction(data)`. +- When `settings.customJsEnabled` is true, the background processing path calls `customUserFunction(data)`. +- The template shows returning modified `data` to continue processing. +- The template shows returning `false` to block/drop a message. +- The template can call helpers such as `sendCustomReply(data, message)`, which builds a response and sends it through `sendMessageToTabs(...)`. + +Example tasks suited to this path: + +- Block all-caps messages. +- Add custom VIP styling. +- Replace keywords. +- Track questions in memory. +- Send auto replies for simple commands. +- Forward donation metadata to a private webhook. + +Agent warning: because this logic runs in the message-processing path, bad code can block messages or flood chat. Tell users to test with a low-risk session before using it live. + +## Custom External Source Via WebSocket + +`sample_wss_source.html` shows how a custom browser page can send SSN-shaped content into a session. + +Core pattern: + +1. Read `session`, `s`, or `id` from the URL. +2. Connect to `wss://io.socialstream.ninja` or `ws://127.0.0.1:3000` with `localserver`. +3. Join the room with an output/input channel pair. +4. Build a data object with SSN message fields. +5. Send it as JSON. + +Minimal message fields: + +```json +{ + "chatname": "steve", + "chatmessage": "Some test message here.", + "chatimg": "https://socialstream.ninja/sources/images/unknown.png", + "type": "external", + "textonly": true +} +``` + +Useful optional fields: + +- `hasDonation` +- `membership` +- `contentimg` +- `chatbadges` +- `sourceName` +- `sourceImg` +- `event` +- `meta` +- `id` + +Use this path when the source is already outside the browser extension, such as: + +- A local bot. +- A private donation service. +- A dashboard or CRM. +- A custom game/app. +- A data source that can produce JSON but should not become an extension content script. + +## WebSocket Source Pages + +`sources/websocket/` contains source pages and helpers for services where an API/WebSocket path is cleaner than DOM capture. + +Examples in the current folder include: + +- `youtube.html` / `youtube.js` +- `twitch.html` / `twitch.js` +- `kick.html` / `kick.js` +- `facebook.html` / `facebook.js` +- `rumble.html` / `rumble.js` +- `irc.html` / `irc.js` +- `streamlabs.html` / `streamlabs.js` +- `bilibili.html` / `bilibili.js` +- `velora.html` / `velora.js` +- `vpzone.html` / `vpzone.js` +- `nostr.html` / `nostr.js` + +These are often used when: + +- The platform has an API/SDK/socket. +- OAuth or creator-owned tokens are required. +- Rich events are needed. +- DOM capture is unreliable. +- The standalone app needs a source page it can load directly. + +## URL Parameters For Customization + +Common custom-source/custom-overlay parameters: + +- `session`, `s`, `id`: session ID. +- `password`: session password. +- `label`: target label for a page instance. +- `server`, `server2`, `server3`: custom WebSocket server routing. +- `localserver`: use local WebSocket server where supported. +- `css`, `cssb64`: custom CSS. +- `js`, `base64js`, `b64js`: custom JavaScript in trusted contexts. +- `postserver`, `putserver`: send selected/featured data to external endpoints. +- `h2rurl`, `h2r`, `spxserver`, `singular`: production graphics integrations. + +Use `parameters.md` for the full list before answering exact parameter support. + +## Support Triage + +When custom behavior fails, ask: -- `social_stream/sources/generic.js` -- `social_stream/sources/README.md` -- `social_stream/custom_sample.js` -- `social_stream/custom_actions.js` -- `social_stream/sample_wss_source.html` -- `social_stream/docs/customoverlays.md` -- `social_stream/README.md` +- Is the user using hosted `socialstream.ninja` pages or local/forked files? +- Is the custom behavior meant for dock/featured, background processing, or an external source? +- Is the page using the same session ID? +- Is the API/server toggle enabled if using WebSocket/HTTP? +- Is the browser console showing JavaScript errors? +- Is the custom script returning `data`, `false`, or `null`? +- Did the user URL-encode custom JS/CSS/API values? +- Does the same workflow work with a simple `clearOverlay` or test message first? -## Starter Notes +## Safety Notes -SSN supports many platform-specific scripts plus generic/custom entry points. This page should bridge user customization and developer source-adding guidance. +- Treat user-supplied JavaScript as powerful and risky. +- Do not recommend pasting untrusted scripts into a live production stream. +- Session IDs and webhook URLs should not be shared publicly. +- Custom responses can get platform accounts rate-limited or banned if they spam chat. +- For platform ToS-sensitive automation, remind users to use bot/timed-message features responsibly. -## Planned Sections +## Follow-Up Extraction Needs -- Generic capture -- Custom scripts -- WSS source examples -- Adding a source -- Debugging capture selectors -- Compatibility with extension and app +- Inspect `sampleoverlay` implementation and document exact custom overlay message listener pattern. +- Build a table of `sources/websocket/*` setup requirements. +- Mine support history for common custom JS mistakes. +- Document Lite customization separately if its behavior differs from the main extension/app pages. diff --git a/docs/agents/08-platform-sources/index.md b/docs/agents/08-platform-sources/index.md index 60f660561..121ab332b 100644 --- a/docs/agents/08-platform-sources/index.md +++ b/docs/agents/08-platform-sources/index.md @@ -1,6 +1,6 @@ # Platform Sources Index -Status: framework only. Detailed extraction not started. +Status: framework plus heavy passes for source inventory, manifest content-script matrix, YouTube, TikTok, Twitch, Kick, Rumble, Facebook, Instagram, Discord, and generic/custom sources. ## Purpose @@ -8,15 +8,17 @@ This section tracks platform-specific source capture behavior. ## High-Priority Pages -- `youtube.md` -- `tiktok.md` -- `twitch.md` -- `kick.md` -- `facebook.md` -- `instagram.md` -- `rumble.md` -- `discord.md` -- `generic-and-custom-sources.md` +- `source-inventory.md`: heavy inventory pass started. +- `manifest-content-scripts.md`: manifest source-load matrix and special content-script flags. +- `youtube.md`: heavy extraction pass complete. +- `tiktok.md`: heavy extraction pass complete. +- `twitch.md`: heavy extraction pass complete. +- `kick.md`: heavy extraction pass complete. +- `facebook.md`: heavy extraction pass started. +- `instagram.md`: heavy extraction pass started. +- `rumble.md`: heavy extraction pass started. +- `discord.md`: heavy extraction pass started. +- `generic-and-custom-sources.md`: heavy extraction pass started. ## Source Anchors @@ -26,3 +28,15 @@ This section tracks platform-specific source capture behavior. - `ssapp/resources/electron-*-handler.js` - `ssapp/tiktok/*` - `stevesbot/resources/learnings/social-stream-ninja-top-issues.md` + +## Suggested Next Pass + +Continue with one of: + +- Intense extraction on TikTok app mode and signing. +- Intense extraction on Kick bridge event normalization and `kick.js` vs `kick_new.js` runtime loading. +- Intense extraction on Rumble API/SSE payloads and popup URL generation. +- Intense extraction on Facebook OAuth/Graph API behavior and viewer-mode support claims. +- Intense extraction on Instagram/Discord popup settings and support-history validation. +- API/Event Flow pass to connect platform events to integration docs. +- Full manifest-to-public-site matrix with all 155 rows, public setup types, and health/status notes. diff --git a/docs/agents/08-platform-sources/instagram.md b/docs/agents/08-platform-sources/instagram.md index 145301477..408fea602 100644 --- a/docs/agents/08-platform-sources/instagram.md +++ b/docs/agents/08-platform-sources/instagram.md @@ -1,10 +1,10 @@ # Instagram Source -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started on 2026-06-24. ## Purpose -Document Instagram and Instagram Live source behavior. +Document SSN's Instagram and Instagram Live content scripts. Instagram has multiple source files because feed/comment capture and live-chat capture have different DOM behavior. ## Source Anchors @@ -13,13 +13,131 @@ Document Instagram and Instagram Live source behavior. - `social_stream/sources/instafeed.js` - `stevesbot/data/sqlite/knowledge.sqlite` -## Starter Notes +## Source Files -Instagram has multiple source files and likely distinct capture flows for feed and live behavior. Detailed extraction is needed before giving confident setup advice. +`sources/instagram.js` and `sources/instagramlive.js` currently contain overlapping logic for: -## Planned Sections +- Instagram Live chat capture. +- Instagram feed/post/comment capture. -- Source differences -- Login/session assumptions -- Capture behavior -- Common support issues +`sources/instafeed.js` is an older/smaller capture path for Instafeed-style live pages and emits `type: "instagramlive"`. + +## Instagram Live Capture + +The live path detects live pages by URL/path patterns containing `/live` and looks for live chat rows in the page DOM. + +It extracts: + +- `chatname` +- `chatmessage` +- `chatimg` +- `chatbadges` +- `hasDonation: ""` +- `membership: ""` +- `contentimg: ""` +- `event` +- `textonly` +- `type: "instagramlive"` + +Important behavior: + +- It uses profile image candidates and visible text to infer the username. +- It treats the text after the username as the message. +- It preserves inline HTML/emoji images when text-only mode is off. +- It rejects rows where name/message are missing or identical. +- A message of `joined` becomes `event: "joined"` only when `settings.capturejoinedevent` is enabled. +- It delays placeholder-looking rows so Instagram's live DOM has time to finish rendering. +- It uses a `MutationObserver` on the live section and can reprocess rows after character-data changes. + +## Instagram Feed/Post Capture + +The feed path processes visible `article` nodes and comment nodes. + +Post payloads include: + +- `chatname` from header link or profile-image alt text. +- `chatmessage` from caption-like nodes. +- `chatimg` +- `contentimg` from post media when available. +- `type: "instagram"` + +Comment payloads include: + +- `chatname` from comment author link or profile image alt text. +- `chatmessage` from the comment message node. +- `chatimg` +- `contentimg` for comment media when available. +- `type: "instagram"` + +Rows are marked with `dataset.ssProcessed` to reduce duplicate sends. + +## Instafeed Capture + +`sources/instafeed.js` extracts from a simpler DOM structure: + +- Username from a `b` element. +- Message from a `span`. +- Avatar image, normalized with `https://instafeed.me` when the path is relative. +- `type: "instagramlive"`. + +It uses a `MutationObserver` and sends through the extension runtime. + +## Login And Session Assumptions + +The current capture paths are DOM readers. They generally need the user to have the relevant Instagram page open in a browser/app context where the messages are visible. They do not show a separate OAuth/token bridge like the Facebook or Kick bridge pages. + +Support answers should avoid promising headless or API-style Instagram capture unless a current source path is verified. + +## Payload Notes + +Instagram Live uses: + +```text +type: instagramlive +``` + +Instagram feed/comments use: + +```text +type: instagram +``` + +Neither path currently sets donation or membership fields from source code reviewed in this pass; those fields are present but empty. + +When text-only mode is off, inline media/emoji markup can be preserved in `chatmessage`. When text-only mode is on, text is escaped/stripped. + +## Common Failures + +No live messages: + +- Confirm the URL is an Instagram Live page. +- Confirm chat rows are visibly appearing. +- Confirm extension capture is enabled. +- Instagram may be delaying/rewriting placeholder rows; wait for actual rendered chat. +- Instagram DOM changes can break selectors. + +Joined events missing: + +- `joined` rows are filtered unless `capturejoinedevent` is enabled. + +Feed/comments missing: + +- Confirm the post/comment is visibly loaded in the page DOM. +- Infinite-scroll/comment expansion may require opening or expanding the comment area before SSN can see rows. +- Already processed nodes are skipped to prevent duplicates. + +Avatar/media missing: + +- Some Instagram media URLs may be blocked, lazy-loaded, or hidden behind DOM changes. +- The capture code only sends `contentimg` when it can find a usable media element. + +Wrong source type in downstream filters: + +- Use `instagramlive` for live chat. +- Use `instagram` for feed/post/comment capture. + +## Remaining Extraction Targets + +- Determine which of `instagram.js` and `instagramlive.js` is loaded for each popup/source path. +- Source-check popup button URLs and any Instagram-specific settings labels. +- Mine support history for current Instagram login/session issues and validate against code. diff --git a/docs/agents/08-platform-sources/kick.md b/docs/agents/08-platform-sources/kick.md index 74d1921bf..01cc2583d 100644 --- a/docs/agents/08-platform-sources/kick.md +++ b/docs/agents/08-platform-sources/kick.md @@ -1,32 +1,175 @@ # Kick Source -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass. Usable for support and architecture orientation, not final field-level docs. ## Purpose -Document Kick capture modes, auth, WebSocket bridge behavior, channel points/rewards, and support issues. +Document Kick capture modes, auth, WebSocket bridge behavior, channel rewards, chat sending, and support issues. ## Source Anchors +- `social_stream/manifest.json` - `social_stream/sources/kick.js` - `social_stream/sources/kick_new.js` - `social_stream/sources/websocket/kick.html` - `social_stream/sources/websocket/kick.js` - `social_stream/providers/kick/core.js` +- `social_stream/docs/event-reference.html` +- `social_stream/docs/kick-channel-points-event-flow.md` - `ssapp/resources/electron-kick-handler.js` - `ssapp/resources/kick-ws-client.js` -- `social_stream/docs/kick-channel-points-event-flow.md` -## Starter Notes +## Runtime Surfaces + +Kick has two important paths: + +- Standard DOM capture from the Kick chatroom/popout page. +- Structured WebSocket/bridge capture from `sources/websocket/kick.html` and `sources/websocket/kick.js`. + +The normal chat path can capture visible chat. The bridge page is the reliable path for structured rewards, subscriptions, follows, raids, KICKs/tips, moderation events, and chat sending. + +## Standard DOM Capture + +`sources/kick_new.js` is the current DOM capture implementation for Kick chat pages. The manifest still references `sources/kick.js`, so future extraction should confirm whether `kick_new.js` is loaded indirectly or is a replacement pending manifest update. + +Confirmed behavior in `sources/kick_new.js`: + +- Rewrites old `https://kick.com/CHANNEL/chatroom` URLs to `https://kick.com/popout/CHANNEL/chat`. +- Detects new popout chat and older chatroom formats. +- Extracts channel/user data from Kick's channel API. +- Polls viewer count from `https://kick.com/api/v2/channels/CHANNEL` when viewer/hype settings are enabled. +- Builds payloads with `type: "kick"`, `chatname`, `chatmessage`, `chatimg`, `chatbadges`, `nameColor`, `hasDonation`, `membership`, `textonly`, `initial`, and `reply`. +- Supports image/SVG badge extraction. +- Detects deleted/line-through messages and sends delete payloads when possible. +- Includes 7TV/emote DOM support where rendered. + +Support setup: + +- Prefer the current popout format: `https://kick.com/popout/CHANNEL/chat`. +- If a user has an older `/chatroom` URL, the source attempts to rewrite it. +- Keep the chat page open and signed in if Kick requires that for badges/profile data. + +## WebSocket/Bridge Capture + +`sources/websocket/kick.js` is the structured Kick integration. + +Confirmed behavior: + +- Loads shared helpers from `providers/kick/core.js` and falls back when needed. +- Initializes extension/app bridge messaging. +- Loads config, URL params, tokens, event type cache, source window config, and authenticated profile. +- Connects Pusher chat without auth after resolving the channel/chatroom. +- Uses OAuth tokens for subscriptions, bridge events, and chat sending. +- Connects a local socket bridge as well as Kick/bridge paths. +- Sends messages through Chrome runtime, `window.ninjafy`, or parent `postMessage` depending on environment. +- Sends delete payloads through the same environment-aware paths. + +Important bootstrap distinction: + +- Pusher chat can connect without auth for chat. +- Auth-dependent features require a Kick OAuth token and active bridge/subscription setup. + +## OAuth And Standalone App Auth + +The standalone app handler `ssapp/resources/electron-kick-handler.js`: + +- Uses loopback host `127.0.0.1`. +- Tries ports `8181` then `8080`. +- Uses callback path `/sources/websocket/kick.html`. +- Uses PKCE with `code_challenge_method=S256`. +- Builds auth URLs at `https://id.kick.com/oauth/authorize`. +- Defaults scopes to `user:read`, `channel:read`, `chat:write`, and `events:subscribe` if the payload does not override scopes. +- Supports external browser auth and a local app auth window mode. +- Local auth window can use app preload variants, including a Kasada preload path. +- Shows a port-conflict dialog if both loopback ports are unavailable. + +Support implication: if Kick OAuth fails in app, check loopback ports, whether auth opened externally or locally, and whether Kick is blocking with human verification/CAPTCHA. + +## Channel Rewards And Event Flow + +`docs/kick-channel-points-event-flow.md` is the best current setup doc. + +Confirmed setup: + +1. Create the reward in Kick. +2. Open `https://socialstream.ninja/sources/websocket/kick.html?channel=YOUR_KICK_CHANNEL`. +3. Click `Sign in with Kick`. +4. Enter/confirm channel slug and click `Connect channel`. +5. Keep the Kick bridge page open. +6. Open the Flow Actions overlay with the same SSN session. +7. In Event Flow Editor, use `User & Source -> Channel Point Redemption`. +8. Set `Reward Name` to the exact Kick reward title, or leave it blank to match any reward. + +Reward payload shape: + +```json +{ + "type": "kick", + "event": "reward", + "chatname": "ViewerName", + "chatmessage": "Sound Alert - optional user input", + "meta": { + "rewardTitle": "Sound Alert", + "rewardId": "123", + "redemptionId": "456", + "cost": 1000, + "status": "fulfilled", + "userInput": "optional user input", + "redeemer": "ViewerName" + } +} +``` + +Key support distinction: the normal Kick chatroom may catch visible "redeemed" text, but the bridge source is the reliable path for structured reward events. + +## Event And Payload Notes + +Important event names from `docs/event-reference.html` and `sources/websocket/kick.js`: + +- Regular bridge chat: no special event or `event: "message"` depending on path. +- `reward`: reward/channel point redemption. +- `new_subscriber`: new subscription. +- `resub`: subscription renewal. +- `subscription_gift`: gifted subs. +- `donation`: KICKs/tips/support events. +- `raid`: incoming host/raid. +- `new_follower`: follow event. +- `follower_update`: total follower count. +- `stream_online` / `stream_offline`: live status. +- `viewer_update`: concurrent viewers from live status or DOM polling. +- `user_banned`: metadata-only moderation event. + +Payload details: + +- Reward meta includes reward/redemption IDs, title, cost, status, user input, redeemed time, description, and redeemer. +- Subscription meta includes subscriber, gifter, total gifted, duration, and plan. +- Donations/KICKs set `hasDonation` and `meta.amount`/`meta.currency`. +- Chat payloads can include `meta.messageId` for delete sync. +- Replies can include `initial`, `reply`, and structured `meta.reply`. +- `providers/kick/core.js` maps and merges badge assets, including image and SVG badges. + +## Common Failures + +- Only chat works, rewards do not: user has normal Kick chat open but not the Kick bridge page. +- Rewards do not trigger Event Flow: bridge page is not signed in, not connected, closed, or using a different SSN session than Flow Actions. +- Wrong reward triggers: set the `Reward Name` filter in the Channel Point Redemption trigger. +- OAuth or chat sending fails: token missing/expired, scope missing, Kick verification/CAPTCHA, or app loopback port conflict. +- Kick says verifying human: use the Chrome extension path or bridge mode in a normal browser when Electron app sign-in is blocked. +- Viewer count missing: verify viewer/hype settings and live channel state. +- Old URL does not work: use `https://kick.com/popout/CHANNEL/chat`. + +## App Vs Extension Differences + +- The extension's DOM path sees the normal browser Kick session. +- The bridge page can run hosted/local and communicate through Chrome runtime or app `window.ninjafy`. +- The standalone app OAuth handler can open Kick auth externally or inside a local app window; that can behave differently under Kick's anti-bot/human-verification flows. +- `ssapp/resources/kick-ws-client.js` is currently a small stub; the main Kick bridge behavior is in `sources/websocket/kick.js`. -Support guidance says Kick often requires pop-out chat and sign-in. Captcha or "verifying human" flows can be platform-side and may affect the standalone app differently than Chrome. +## Extraction Notes -## Planned Sections +Needs intense pass: -- Standard source -- WebSocket source -- App bridge behavior -- OAuth/sign-in -- Channel points/rewards -- Event Flow setup -- Common failures +- Confirm `kick.js` vs `kick_new.js` manifest/runtime loading relationship. +- Exact Kick bridge scope set and token refresh behavior. +- Full event type normalization table in `sources/websocket/kick.js`. +- Chat send retry/error handling and moderation action behavior. diff --git a/docs/agents/08-platform-sources/manifest-content-scripts.md b/docs/agents/08-platform-sources/manifest-content-scripts.md new file mode 100644 index 000000000..13d97ae9c --- /dev/null +++ b/docs/agents/08-platform-sources/manifest-content-scripts.md @@ -0,0 +1,171 @@ +# Manifest Content Script Matrix + +Status: heavy inventory pass started from `manifest.json`. This page summarizes source-load behavior for agent routing; the manifest remains the exact source of truth. + +## Purpose + +Use this page when a user asks which file handles a platform URL, why a source script loads in an iframe, why a source must run at `document_start`, or whether a public site card has an actual extension content-script match. + +For exact URL pattern answers, inspect `manifest.json` directly. + +## Source Anchors + +- `manifest.json` +- `sources/*.js` +- `sources/static/*` +- `sources/inject/*` +- `sources/websocket/*` +- `shared/vendor/socket.io.min.js` +- `docs/agents/08-platform-sources/source-inventory.md` +- `docs/agents/12-development/adding-a-source.md` + +## Current Manifest Counts + +Checked on 2026-06-24 against manifest version `3.50.1`. + +| Inventory | Count | Notes | +| --- | ---: | --- | +| Content-script entries | 155 | Each entry is a manifest object with one or more URL match patterns. | +| Unique JS files loaded by content scripts | 155 | One unique JS file per content-script entry in the current manifest. | +| Top-level `sources/*.js` scripts | 135 | Normal platform/source DOM capture scripts. | +| `sources/static/*` helpers | 6 | Manual/static/scout helpers, not normal live-chat capture scripts. | +| `sources/inject/*` helpers | 2 | Page-context helpers that run early for specific platforms. | +| `sources/websocket/*` source-page scripts | 11 | Scripts loaded on hosted/beta WebSocket source pages. | +| Other shared scripts | 1 | `shared/vendor/socket.io.min.js`, currently for Velora WebSocket source pages. | +| `document_start` entries | 8 | Early-load scripts. Usually fragile or page-context sensitive. | +| `all_frames` entries | 18 | Scripts that can run inside iframes as well as the top page. | +| `match_about_blank` entries | 0 | None currently observed. | + +## Content Script Buckets + +| Bucket | Files | What It Usually Means | +| --- | --- | --- | +| Top-level source scripts | `sources/*.js` | Extension injects directly into platform pages or popout chat pages. | +| Static helper scripts | `sources/static/*.js` | Manual/static capture, source scouting, or helper behavior on a broader site page. | +| Injected helper scripts | `sources/inject/*.js` | Early page-context access for platform internals, often paired with a normal source script. | +| WebSocket source scripts | `sources/websocket/*.js` | Hosted SSN source pages that connect to platform APIs/WebSockets and then forward into SSN. | +| Shared vendor scripts | `shared/vendor/*.js` | Local vendored dependency loaded by a source page. This is not a remote executable dependency. | + +## Static Helpers In Manifest + +- `sources/static/claude.js` +- `sources/static/kick_chatroom_scout.js` +- `sources/static/threads.js` +- `sources/static/twitch_points.js` +- `sources/static/x.js` +- `sources/static/youtube_static.js` + +Support note: static helpers often require an explicit user action or source toggle. Do not treat them as normal automatic live-chat capture without checking the platform doc. + +## Injected Helpers In Manifest + +| Script | Sample URL Patterns | Notes | +| --- | --- | --- | +| `sources/inject/vpzone-ws.js` | `https://vpzone.tv/*`, `https://www.vpzone.tv/*`, `https://*.vpzone.tv/*` | Runs at `document_start`; paired with VPZone source behavior. | +| `sources/inject/whatnot-ws.js` | `https://www.whatnot.com/live/*`, `https://www.whatnot.com/dashboard/live/*` | Runs at `document_start`; paired with Whatnot source behavior. | + +Support note: injected helpers are high-risk when a platform changes its page internals. Check recent source code and support notes before making strong claims. + +## WebSocket Source Scripts In Manifest + +These are loaded on hosted/beta SSN source-page URLs, not directly on the third-party platform page: + +- `sources/websocket/bilibili.js` +- `sources/websocket/facebook.js` +- `sources/websocket/irc.js` +- `sources/websocket/joystick.js` +- `sources/websocket/kick.js` +- `sources/websocket/nostr.js` +- `sources/websocket/rumble.js` +- `sources/websocket/twitch.js` +- `sources/websocket/velora.js` +- `sources/websocket/vpzone.js` +- `sources/websocket/youtube.js` + +Most of these entries match multiple hosted/beta URL variants, such as `socialstream.ninja`, `beta.socialstream.ninja`, and `/beta/` paths. + +## Early Or Multi-Frame Entries + +These manifest entries have `document_start` and/or `all_frames` enabled. They deserve extra care because load timing and frame context can affect behavior. + +| Index | Script | Matches | Run At | All Frames | Sample Pattern | +| ---: | --- | ---: | --- | --- | --- | +| 2 | `sources/stripchat.js` | 3 | default | yes | `https://stripchat.com/*` | +| 7 | `sources/meetme.js` | 2 | default | yes | `https://*.meetme.com/*` | +| 39 | `sources/steam.js` | 1 | default | yes | `https://steamcommunity.com/broadcast/chatonly/*` | +| 40 | `sources/megaphonetv.js` | 1 | default | yes | `https://apps.megaphonetv.com/socialharvest/live/*` | +| 43 | `sources/inject/vpzone-ws.js` | 3 | `document_start` | no | `https://vpzone.tv/*` | +| 52 | `sources/inject/whatnot-ws.js` | 2 | `document_start` | no | `https://www.whatnot.com/live/*` | +| 63 | `sources/cbox.js` | 1 | default | yes | `https://*.cbox.ws/box/*` | +| 80 | `sources/youtube.js` | 1 | default | yes | `https://studio.youtube.com/live_chat*` | +| 88 | `sources/wix2.js` | 1 | default | yes | `https://editor.wixapps.net/render/prod/modals/wix-vod-widget/*` | +| 93 | `sources/static/kick_chatroom_scout.js` | 1 | `document_start` | no | `https://kick.com/*` | +| 110 | `sources/minnit.js` | 3 | default | yes | `https://minnit.chat/*&popout` | +| 111 | `sources/chatroll.js` | 1 | default | yes | `https://chatroll.com/embed/chat/*` | +| 118 | `sources/twitch.js` | 1 | `document_start` | no | `https://*.twitch.tv/popout/*` | +| 119 | `sources/static/twitch_points.js` | 1 | `document_start` | no | `https://*.twitch.tv/*` | +| 121 | `sources/ebay.js` | 22 | default | yes | `https://www.ebay.com/ebaylive/events/*` | +| 128 | `sources/vimeo.js` | 3 | default | yes | `https://www.vimeo.com/live*` | +| 132 | `sources/teams.js` | 3 | default | yes | `https://teams.live.com/*` | +| 137 | `sources/tikfinity.js` | 2 | default | yes | `https://tikfinity.zerody.one/widget/activity-feed*` | +| 138 | `sources/vdoninja.js` | 3 | default | yes | `https://vdo.ninja/popout.html*` | +| 140 | `sources/webex.js` | 2 | default | yes | `https://*.webex.com/*` | +| 144 | `sources/trovo.js` | 1 | `document_start` | yes | `https://trovo.live/chat/*` | +| 145 | `sources/amazon.js` | 2 | `document_start` | no | `https://www.amazon.com/live*` | +| 153 | `sources/streamlabs.js` | 2 | default | yes | `https://streamlabs.com/alert-box/*` | +| 154 | `sources/streamelements.js` | 1 | `document_start` | yes | `https://streamelements.com/overlay/*` | + +## High-Coverage URL Match Entries + +These scripts have four or more manifest match patterns. This usually means broad domain coverage, multiple hosted variants, or several public URL shapes. + +| Script | Match Count | Sample Patterns | +| --- | ---: | --- | +| `sources/ebay.js` | 22 | `https://www.ebay.com/ebaylive/events/*`; `https://www.ebay.co.uk/ebaylive/events/*`; `https://www.ebay.de/ebaylive/events/*` | +| `sources/x.js` | 9 | `https://www.twitter.com/*`; `https://twitter.com/*`; `https://x.com/*/chat` | +| `shared/vendor/socket.io.min.js` | 6 | `https://socialstream.ninja/sources/websocket/velora*`; `https://beta.socialstream.ninja/sources/websocket/velora*`; `https://socialstream.ninja/beta/sources/websocket/velora*` | +| `sources/websocket/bilibili.js` | 6 | hosted/beta Bilibili source page variants | +| `sources/websocket/facebook.js` | 6 | hosted/beta Facebook source page variants | +| `sources/websocket/irc.js` | 6 | hosted/beta IRC source page variants | +| `sources/websocket/joystick.js` | 6 | hosted/beta Joystick source page variants | +| `sources/websocket/kick.js` | 6 | hosted/beta Kick source page variants | +| `sources/websocket/rumble.js` | 6 | hosted/beta Rumble source page variants | +| `sources/websocket/twitch.js` | 6 | hosted/beta Twitch source page variants | +| `sources/websocket/velora.js` | 6 | hosted/beta Velora source page variants | +| `sources/websocket/vpzone.js` | 6 | hosted/beta VPZone source page variants | +| `sources/websocket/youtube.js` | 6 | hosted/beta YouTube source page variants | +| `sources/facebook.js` | 5 | `https://facebook.com/*`; `https://web.facebook.com/*`; `https://www.facebook.com/*` | +| `sources/loco.js` | 5 | `https://*.loco.gg/*`; `https://loco.gg/streamers/*`; `https://*.loco.com/*` | +| `sources/websocket/nostr.js` | 5 | hosted/beta Nostr source page variants | +| `sources/circle.js` | 4 | `https://community.insidethe.show/*`; `https://community.talkinghealthtech.com/*`; `https://members.firstinfam.com/*` | +| `sources/kick.js` | 4 | `https://kick.com/*/chatroom`; `https://kick.com/*/*/chatroom`; `https://kick.com/popout/*/chat` | +| `sources/rumble.js` | 4 | `https://rumble.com/chat/popup/*`; `https://rumble.com/*/live`; `https://www.rumble.com/chat/popup/*` | +| `sources/tiktok.js` | 4 | `https://www.tiktok.com/*live*`; `https://livecenter.tiktok.com/*`; `http://localhost:8080/*/fav.html` | +| `sources/youtube.js` | 4 | `https://www.youtube.com/watch?v=*&socialstream`; `https://youtube.com/live_chat*`; `https://www.youtube.com/live_chat*` | +| `sources/zoom.js` | 4 | `https://*.zoom.us/*`; `https://zoom.us/*`; `https://*.zoom.com/*` | + +## How To Answer "Which File Handles This URL?" + +Use this order: + +1. Search `manifest.json` for the domain or URL shape. +2. Note the matched content-script file and whether it is top-level, static, injected, WebSocket, or shared vendor. +3. If it is a top-level script, inspect `sources/.js`. +4. If it is a WebSocket script, inspect the paired `sources/websocket/.html` and `.js`. +5. If it is static or injected, check whether a normal source script also exists for the same platform. +6. Cross-check the public setup type in `docs/js/sites.js` and `source-inventory.md`. + +Safe answer shape: + +```text +The extension match for that URL is in `manifest.json` and loads `[script]`. That means this is a [normal/static/injected/websocket] source path. For exact behavior, inspect `[script]` and the platform agent page before promising specific events or send-chat support. +``` + +## Extraction Gaps + +Needed intense passes: + +- Generate a full 155-entry manifest table and map each row to a public site card, when one exists. +- Reconcile manifest-only helper/source entries that do not have public `docs/js/sites.js` cards. +- Mark send-chat, event richness, auth, popout, and source-toggle requirements per manifest row. +- Verify whether `document_start` and `all_frames` entries still need those flags. diff --git a/docs/agents/08-platform-sources/rumble.md b/docs/agents/08-platform-sources/rumble.md index c52295478..ace6cdef5 100644 --- a/docs/agents/08-platform-sources/rumble.md +++ b/docs/agents/08-platform-sources/rumble.md @@ -1,10 +1,10 @@ # Rumble Source -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started on 2026-06-24. ## Purpose -Document Rumble source setup, popup URL formats, WebSocket source behavior, and known support issues. +Document SSN's Rumble capture paths: normal DOM capture on Rumble pages and the newer Rumble Live Stream API bridge. ## Source Anchors @@ -13,14 +13,180 @@ Document Rumble source setup, popup URL formats, WebSocket source behavior, and - `social_stream/sources/websocket/rumble.js` - `stevesbot/resources/learnings/social-stream-ninja-top-issues.md` -## Starter Notes +## Capture Modes -Support summaries mention exact Rumble URL formats and verification loops. These claims need source verification and current-code checks. +### Normal Rumble Page Capture -## Planned Sections +`sources/rumble.js` is a Chrome extension content script that watches Rumble chat DOM rows with a `MutationObserver`. -- Popup chat URL -- Live page URL fallback -- WebSocket source -- Verification/user-agent issues -- Common failures +It extracts: + +- `chatname` +- `chatmessage` +- `chatimg` +- `chatbadges` +- `nameColor` +- `hasDonation` from rant price elements +- `contentimg` for raid background images +- `event: "raid"` for raid containers +- `sourceImg` from the channel/creator image when available +- `textonly` +- `type: "rumble"` + +It converts avatar/source images to data URLs where possible before relaying. This helps downstream overlays keep rendering when source images would otherwise be blocked or short-lived. + +### Rumble Live Stream API Bridge + +`sources/websocket/rumble.html` and `sources/websocket/rumble.js` implement a read-only bridge for Rumble's creator Live Stream API URL. + +The UI tells users to paste the private URL from: + +```text +rumble.com/account/livestream-api +``` + +The bridge can relay normalized: + +- Chat messages. +- Rants/donations. +- Followers. +- Subscribers. +- Gifted subscriptions. +- Viewer counts. +- Stream online/offline state. + +It is read-only. Sending messages through the Rumble API is not supported in this bridge. + +## API Bridge Setup + +1. Open the Rumble API dashboard. +2. Generate the Live Stream API URL for the creator/user/channel to monitor. +3. Paste that private URL into the Rumble API Alerts page. +4. Click Connect. +5. Keep the page open while it should relay into SSN. + +The UI warns that the API URL is private because it already includes the stream key. If leaked, the user should reset it from the Rumble dashboard. + +Supported URL parameters shown in the page: + +- `apiUrl` +- `channel` +- `streamId` +- `poll` +- `replay` +- `sse` +- `followerMode` + +Example: + +```text +sources/websocket/rumble.html?apiUrl=...&channel=MyChannel&poll=3000 +``` + +## API Bridge Payloads + +Base payload fields: + +- `chatbadges` +- `backgroundColor` +- `textColor` +- `chatimg` +- `hasDonation` +- `membership` +- `contentimg` +- `textonly` +- `type: "rumble"` +- `sourceName` +- `sourceImg` + +Chat payloads include: + +- `chatname` +- `chatmessage` +- `chatbadges` +- `meta.source: "live_stream_api"` for documented API polling +- `meta.source: "rumble_sse"` for SSE chat +- stream ID/title and timestamps where available +- `meta.plainText` +- `meta.rumbleEmotesRendered` when emotes were rendered into HTML + +Rant/donation payloads set: + +- `event: "donation"` +- `hasDonation` to the formatted amount +- `meta.rant: true` +- amount/currency details where available + +Follower payloads set: + +- `event: "new_follower"` +- `chatmessage` like `Started following` + +Subscriber payloads set: + +- `event: "new_subscriber"` +- `membership` to the subscriber label +- `subtitle` to the amount label when present + +Gift payloads set: + +- `event: "subscription_gift"` +- `membership` to the subscriber label +- `hasDonation` to a gifted count label +- `meta.totalGifted`, `remainingGifts`, `giftType`, and `videoId` + +Viewer/stream status events are emitted as event-style messages, not normal chat messages. + +## SSE And Polling Behavior + +The bridge supports SSE-style chat retrieval and falls back to documented API chat polling when SSE fails. It deduplicates messages with seen event IDs and can seed recent history without relaying it unless replay is enabled. + +Default poll interval in the UI is `3000` ms. Advanced UI allows a range from `1500` to `15000` ms. Lower intervals update faster but create more requests. + +## Normal Page Payload Notes + +DOM capture differs from API bridge capture: + +- It depends on Rumble's current page markup. +- It can see visible chat DOM elements on the opened page. +- It marks raids with `event: "raid"`. +- It captures rant prices from the visible page as `hasDonation`. +- It does not require the private Live Stream API URL. + +Use the API bridge when a creator can provide the API URL and wants structured, less DOM-fragile event capture. + +## Common Failures + +No messages from API bridge: + +- The API URL is missing, wrong, expired, or reset. +- The user is not live and expects live chat/viewer data. +- The bridge page was closed. +- The user selected a stream ID that is not the active livestream. + +No chat from normal page capture: + +- The wrong Rumble page/chat page is open. +- Rumble changed DOM markup and selectors need review. +- Extension capture is off or settings are not loaded. +- The source tab is inactive, throttled, or not showing new chat rows. + +Rants/followers/subscribers missing: + +- Confirm whether the user is using the API bridge or normal DOM capture. The API bridge has structured support for these events; normal DOM capture only sees what appears in the page DOM. +- Check whether the event type exists in the current API response. + +Duplicate or old messages: + +- The API bridge has replay and seed behavior. Disable replay if recent history should not be forwarded on connect. +- Normal DOM capture has different dedupe behavior and can be affected by Rumble re-rendering old rows. + +Security concern: + +- Treat the Rumble Live Stream API URL like a secret. Do not paste it into public logs or screenshots. + +## Remaining Extraction Targets + +- Source-check exact popup button URL generation from `popup.js`. +- Confirm all support-mined Rumble URL-format advice against current popup/source code. +- Line-level review of stream online/offline and viewer count payloads in `sources/websocket/rumble.js`. diff --git a/docs/agents/08-platform-sources/source-inventory.md b/docs/agents/08-platform-sources/source-inventory.md new file mode 100644 index 000000000..4bbda85d5 --- /dev/null +++ b/docs/agents/08-platform-sources/source-inventory.md @@ -0,0 +1,459 @@ +# Source Inventory + +Status: heavy inventory pass started from public site metadata, manifest, and source folders. This page is an orientation map, not proof that every source currently works. + +## Source Anchors + +- `docs/js/sites.js` +- `docs/supported-sites.html` +- `README.md` +- `manifest.json` +- `sources/*.js` +- `sources/static/*` +- `sources/inject/*` +- `sources/websocket/*` +- `docs/agents/08-platform-sources/*.md` +- `docs/agents/13-reference/modes-and-capability-matrix.md` + +## Counts Observed + +Checked on 2026-06-24. + +| Inventory | Count | Notes | +| --- | ---: | --- | +| Public supported-site entries in `docs/js/sites.js` | 139 | User-facing site cards grouped by setup type. | +| `manifest.json` content-script entries | 155 | Implementation URL match entries. Some entries are helpers/source pages, not public site cards. | +| Top-level `sources/*.js` files | 143 | Includes active, helper, generic, duplicate/new variants, and source-specific utilities. | +| `sources/websocket/*` HTML/JS files | 28 | 14 page/script pairs or near-pairs, plus shared source-page assets. | +| Manifest top-level source scripts | 135 | Unique `./sources/*.js` scripts referenced directly by manifest content scripts. | +| Manifest static helper scripts | 6 | `sources/static/*` scripts referenced by manifest. | +| Manifest injected helper scripts | 2 | `sources/inject/*` scripts referenced by manifest. | +| Manifest WebSocket source scripts | 11 | `sources/websocket/*.js` scripts referenced by manifest. | + +Important rule: the public site list, manifest entries, and source files are overlapping but not identical. For a support answer, check all three when precision matters. + +## Public Site Setup Types + +`docs/js/sites.js` currently classifies public site cards into these types: + +| Type | Count | Meaning | +| --- | ---: | --- | +| `standard` | 100 | User normally opens the site/page directly; no public "popout required" tag. | +| `popout` | 23 | Public setup expects a popout chat or equivalent popout URL. | +| `toggle` | 9 | Requires an explicit SSN setting/menu toggle before capture. | +| `websocket` | 4 | Public setup points at an SSN WebSocket/API source page. | +| `manual` | 3 | User manually selects/pushes content. | + +## Public Popout Entries + +- Beamstream +- BoltPlus.tv +- Chzzk.naver.com +- Fansly +- Favorited +- FloatPlane +- GoodGame.ru +- Kick.com +- Mixcloud Live +- Nimo.TV +- Odysee +- Parti +- Picarto.tv +- Piczel.tv +- RokFin +- Rumble +- Rutube +- SoopLive +- Twitch +- VDO.Ninja +- VK Play Live +- X Live (Twitter) +- YouTube Live + +Support note: if one of these sources is not capturing, first verify that the user opened the required popout/chat URL and reloaded it after enabling/reloading SSN. + +## Public Toggle-Required Entries + +- ChatGPT +- Claude.ai +- Discord +- Google Meet +- Instagram Post Comments +- Patreon +- Slack +- Telegram +- WhatsApp Web + +Support note: for these, first verify the specific source toggle is enabled in settings, then reload the target site. + +## Public Manual Entries + +- Threads.net +- X Static Posts +- YouTube Static Comments + +Support note: these are not normal automatic live-chat capture paths. The user must manually select/push content from the page. + +## Public WebSocket Entries + +- IRC WebSocket +- Joystick Bot WebSocket +- Rumble API URL +- Twitch IRC WebSocket + +Support note: these public entries represent source-page/API workflows. They can differ from DOM capture in setup, event coverage, and send-chat support. + +## Public Standard Entries + +- Amazon Chime +- Amazon Live +- Arena Social +- BandLab +- Bigo.tv +- Bilibili.com +- Bilibili.tv +- Bitchute +- Blaze +- Blaze.stream +- Bongacams +- Buzzit +- CAM4 +- Camsoda +- Castr +- CBOX +- Chatroll +- Chaturbate +- Cherry TV +- CI.ME +- Circle.so +- CloutHub +- Cozy.tv +- Crowdcast.io +- eBay Live +- Estrim +- Facebook Live +- FC2 +- Gala Music +- Instafeed +- Instagram Live +- IRC KiwiIRC +- IRC Quakenet +- Jaco.live +- Joystick.tv +- LFG.tv +- LinkedIn Events +- LivePush +- Livestorm.io +- Locals.com +- Loco.gg +- MeetMe +- MegaphoneTV +- Microsoft Teams +- Minnit Chat +- Mixlr +- Moonbeam +- MyFreeCams +- NextCloud +- NicoVideo +- Noice +- NonOLive +- On24 +- ON24 +- Online Church +- Owncast +- PeerTube +- Pilled.net +- Portal +- Pump.fun +- QuickChannel +- Restream.io Chat +- Retake.tv +- Riverside.fm +- Roll20 +- Rooter +- Rozy.tv +- Sessions.us +- SharePlay.tv +- Simps +- Slido +- SoulBound.tv +- StageTEN.tv +- Steam Broadcasts +- Stream.place +- Stripchat +- Substack +- Tellonym +- TikTok Live +- TradingView Streams +- Truffle.vip +- TwitCasting +- uScreen +- Velora.tv +- Vercel Demo +- Versus.cam +- Vertical Pixel Zone +- Vimeo +- VK Live +- VPZone.tv +- Wave Video +- Webex +- WebinarGeek +- Whatnot +- Whop +- Wix Live +- Xeenon +- YouNow +- Zap.stream +- Zoom + +Support note: "standard" does not mean "always works with any URL". Verify the exact match pattern in `manifest.json` and the parser in `sources/*.js`. + +## Manifest WebSocket Source Scripts + +These `sources/websocket/*.js` files are currently referenced by `manifest.json`: + +- `sources/websocket/bilibili.js` +- `sources/websocket/facebook.js` +- `sources/websocket/irc.js` +- `sources/websocket/joystick.js` +- `sources/websocket/kick.js` +- `sources/websocket/nostr.js` +- `sources/websocket/rumble.js` +- `sources/websocket/twitch.js` +- `sources/websocket/velora.js` +- `sources/websocket/vpzone.js` +- `sources/websocket/youtube.js` + +The `sources/websocket/` folder also contains page/script pairs for: + +- Bilibili +- Facebook +- IRC +- Joystick +- Kick +- Nostr +- Rumble +- Social Stream Chat +- StageTEN +- Streamlabs +- Twitch +- Velora +- VPZone +- YouTube + +Not every page in the folder has the same manifest/public-doc status. Verify before promising support. + +## Manifest Static And Injected Helpers + +Static helper scripts referenced by manifest: + +- `sources/static/claude.js` +- `sources/static/kick_chatroom_scout.js` +- `sources/static/threads.js` +- `sources/static/twitch_points.js` +- `sources/static/x.js` +- `sources/static/youtube_static.js` + +Injected helper scripts referenced by manifest: + +- `sources/inject/vpzone-ws.js` +- `sources/inject/whatnot-ws.js` + +These helpers are not the same as ordinary DOM source scripts. They often support manual/static capture or page-context access. + +## Top-Level Source Scripts + +The top-level `sources/*.js` folder currently contains 143 JavaScript files: + +```text +amazon.js +arenasocial.js +autoreload.js +bandlab.js +beamstream.js +bigo.js +bilibili.js +bilibilicom.js +bitchute.js +blaze.js +boltplus.js +bongacams.js +buzzit.js +cam4.js +camsoda.js +capturevideo.js +castr.js +cbox.js +chatroll.js +chaturbate.js +cherrytv.js +chime.js +chzzk.js +cime.js +circle.js +cloudhub.js +cozy.js +crowdcast.js +discord.js +dlive.js +ebay.js +estrim.js +facebook.js +fansly.js +favorited.js +fc2.js +floatplane.js +gala.js +generic.js +goodgame.js +grabvideo.js +instafeed.js +instagram.js +instagramlive.js +jaco.js +joystick.js +kick.js +kick_new.js +kiwiirc.js +kwai.js +lfg.js +linkedin.js +livepush.js +livestorm.js +livestream.js +locals.js +loco.js +meetme.js +meets.js +megaphonetv.js +minnit.js +mixcloud.js +mixlr.js +myfreecams.js +nextcloud.js +nicovideo.js +nimo.js +nonolive.js +odysee.js +on24.js +onlinechurch.js +openai.js +openstreamingplatform.js +owncast.js +parti.js +patreon.js +peertube.js +picarto.js +piczel.js +pilled.js +portal.js +pumpfun.js +quakenet.js +quickchannel.js +restream.js +retake.js +riverside.js +rokfin.js +roll20.js +rooter.js +rumble.js +rutube.js +sessions.js +shareplay.js +simps.js +slack.js +slido.js +sooplive.js +soulbound.js +steam.js +streamelements.js +streamlabs.js +streamplace.js +stripchat.js +substack.js +teams.js +telegram.js +telegramk.js +tellonym.js +tikfinity.js +tiktok.js +tradingview.js +trovo.js +truffle.js +twitcasting.js +twitch.js +uscreen.js +vdoninja.js +velora.js +vercel.js +verticalpixelzone.js +vimeo.js +vklive.js +vkplay.js +vkvideo.js +vpzone.js +wavevideo.js +webex.js +webinargeek.js +whatnot.js +whatsapp.js +whop.js +wix.js +wix2.js +workplace.js +x.js +xeenon.js +younow.js +youtube.js +youtube_comments.js +youtube_static.js +zapstream.js +zoom.js +``` + +## Graveyard And Deprecated Sources + +`sources/graveyard/` contains retired/old source files and icons. Do not treat those as current support without checking current docs and manifest entries. + +Observed graveyard examples include: + +- AfreecaTV / Sooplive old variant +- Arena/Arena Social old variants +- Caffeine +- DLive old variant +- Glimesh +- Livespace +- Moonbeam +- Noice +- Omlet +- Soulbound old variant +- StageTEN old variant +- Theta +- Trovo old variant +- Twitter old variant +- Vimm +- Vstream +- Xeenon old variant + +## How To Answer "Is X Supported?" + +Use this order: + +1. Check `docs/js/sites.js` or `docs/supported-sites.html` for public user-facing support and setup type. +2. Check `manifest.json` for URL match patterns. +3. Check `sources/*.js`, `sources/static/*`, `sources/inject/*`, or `sources/websocket/*` for current implementation. +4. Check platform-specific agent docs and support-history pages for known breakage. +5. State the setup mode and any caveat. + +Safe answer shape: + +```text +It is listed as supported as a [standard/popout/toggle/manual/websocket] source. Use [setup detail]. I would still verify the current source file and recent support notes before promising a specific event or send-chat feature. +``` + +## Follow-Up Extraction Needs + +- Generate a manifest-derived table mapping every content script to URL patterns and public site names. +- Mark which public site entries have matching top-level scripts, WebSocket pages, static helpers, or injected helpers. +- Add health/status columns from recent support history. +- Reconcile duplicate public names, such as `On24` / `ON24` and `Blaze` / `Blaze.stream`. diff --git a/docs/agents/08-platform-sources/tiktok.md b/docs/agents/08-platform-sources/tiktok.md index 3699f0e0f..1f83dc7b6 100644 --- a/docs/agents/08-platform-sources/tiktok.md +++ b/docs/agents/08-platform-sources/tiktok.md @@ -1,32 +1,151 @@ # TikTok Source -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass. Usable for support and architecture orientation, not final field-level docs. ## Purpose -Document TikTok standard mode, WebSocket mode, signing, app-specific connection management, and common support problems. +Document TikTok standard mode, WebSocket/app mode, signing, app-specific connection management, event handling, and common support problems. ## Source Anchors +- `social_stream/manifest.json` - `social_stream/sources/tiktok.js` +- `social_stream/docs/tiktok-guide.html` +- `social_stream/docs/event-reference.html` - `ssapp/tiktok/connection-manager.js` - `ssapp/tiktok-signing/electron-signer.js` - `ssapp/tiktok-auth.js` - `ssapp/tiktok-badges.js` - `ssapp/tests/tiktok/*` -- `social_stream/docs/tiktok-guide.html` -- `stevesbot/resources/learnings/playbooks/playbook-tiktok-connection.md` +- `stevesbot/resources/instructions/social-stream-support.md` +- `stevesbot/resources/learnings/social-stream-ninja-top-issues.md` + +## High-Level Guidance + +TikTok is one of the most fragile SSN platforms. The public TikTok guide explicitly says TikTok changes often and not every account sees the same behavior. + +Current recommendation from `docs/tiktok-guide.html`: + +- Start with `TikTok WS + Auto` for reading. +- Use `Standard` if replies matter. +- Use `TikTok WS + Local Signer` when Standard is unstable but replies are still needed. +- Use `Polling` as compatibility mode when WebSocket paths fail. +- Use `TikFinity OBS Dock` as a read-only fallback when TikTok native paths miss too much chat or fail to connect. + +## Browser Extension Standard DOM Mode + +`sources/tiktok.js` is the browser-page DOM capture source. + +Confirmed behavior: + +- The manifest injects it on TikTok live pages. +- It forwards messages with `chrome.runtime.sendMessage(chrome.runtime.id, { message: data })`. +- Normal payloads use `type: "tiktok"`. +- It builds payloads with fields such as `chatname`, `chatbadges`, `nameColor`, `chatmessage`, `chatimg`, `hasDonation`, `membership`, `contentimg`, `textonly`, and `event`. +- It detects event hints from rendered social/system cards. +- It skips TikTok welcome/community-filter boilerplate and duplicate messages. +- It tracks top-viewer/member-level metadata when the page exposes it. +- It uses avatar caching so later social/event rows can inherit avatar/badge/member data from previous chat rows. + +Standard mode is best when the user needs replies from SSN and the live TikTok page is visible/usable. + +## TikTok DOM Events + +Confirmed from `sources/tiktok.js` and `docs/event-reference.html`: + +- Regular chat: no special event value. +- Gift rows: `event: "gift"` and `hasDonation` such as `N coins`, `N coin`, `N gifts`, or a gift name/count fallback. +- Join events: `event: "joined"` when capture settings allow join events. +- Follow events: `event: "followed"`; the code requires a `chatname`. +- Like events: `event: "liked"`. +- Generic social/system broadcasts may use boolean `true` as the event value when no subtype is known. +- Share events are detected but standard DOM code currently returns instead of forwarding them in some paths. + +The event reference also documents TikFinity activity-feed rows using canonical TikTok fields for chat, follows, shares, gifts, subscriptions, joins, and treasure chests. + +## App Native/WebSocket Mode + +The standalone app has a much larger TikTok stack in `ssapp/tiktok/connection-manager.js`. + +Confirmed responsibilities: + +- Uses `tiktok-live-connector` and `@eulerstream/euler-websocket-sdk`. +- Maintains app-side connection managers keyed by WebSocket/source IDs. +- Supports modern Euler WebSocket provider behavior and legacy connector fallback. +- Tracks active TikTok connections by source ID and avoids forwarding messages for inactive/reply-only connections. +- Uses virtual tab IDs starting at `900000 + wssID` to route TikTok app messages through the app/background path. +- Forwards single messages and batches into the Social Stream background frame via `frame.postMessage("fromMain", payload)`, with retry logic. +- Calls `env.onEvent(msg)` for app-side event hooks before forwarding. +- Adds `meta.ssnAccountRole`, `meta.ssnSourceId`, and `meta.ssnSession` for non-normal source account roles. + +App event support is broader than DOM capture. `docs/event-reference.html` notes app native mode adds events beyond page/widget capture, including `question_new`, `emote`, and `viewer_update`. + +## Signing And Replies + +Reply support depends on a valid signed-in TikTok session. + +Confirmed from docs and app code: + +- `Standard` is the first-choice reply mode. +- `Local Signer` is the fallback reply mode. +- `Auto`, `Polling`, and TikFinity are not meant for replies. +- The app has a direct room/chat route when `tiktok-live-connector` exposes `SendRoomChatRoute`. +- Local signer paths may sign `X-Bogus`, `X-Gnarly`, `_signature`, `msToken`, and related request data. +- Direct chat sends require a TikTok `sessionid` cookie; the connection manager logs/returns an error if it is missing. +- Under local signer, Euler chat fallback can be disabled; the app prefers the active WebSocket connection or direct route depending on mode and availability. + +Support implication: if reading works but replies fail, ask which TikTok mode is active and whether the user is signed into the TikTok account that should send messages. + +## Gift And Emote Handling + +Confirmed behavior: + +- DOM mode parses TikTok gift image URLs and quantities from rendered HTML. +- Gift values are mapped through `giftMapping`; when coin values are unavailable, it falls back to gift names or generic gift counts. +- App mode has richer gift/emote handling, including `gift-mapping.json`, emote normalization, top-gifter badges, and text-only rendering paths. +- App chat payloads preserve upstream IDs/timestamps when available for dedupe/debugging. + +Gift combo duplicates are historically common support noise. The current code includes duplicate suppression in both DOM and app paths, but TikTok reconnects and gift rendering can still create edge cases that need intense validation. + +## Testing And Diagnostics + +`ssapp/tests/tiktok/run.js` supports: + +- `--mode=websocket` +- `--mode=legacy` +- `--mode=both` +- `--user=username` +- `--duration=milliseconds` +- `--capture-likes` + +The test runner creates a TikTok environment, initializes a `ConnectionManager`, logs status, and summarizes forwarded events. Additional regression files cover auto mode, fuzzing, gift counts, dedupe/replay, authenticated bootstrap, single active connection, social signals, chat emotes, and 403 bug validation. + +## Common Failures + +- User is not live: TikTok chat capture often fails or reports offline if the account is not actually live. +- Username format: use the username without `@` unless the UI explicitly asks for a URL. +- Missing messages: can be TikTok-side, account-specific, region-specific, or mode-specific. Try another mode before treating it as a code bug. +- Auth window closes or CAPTCHA appears: use `Show capture page`, sign in visibly, then reload. +- Replies fail: use Standard or Local Signer and verify signed-in session/cookies. +- Rate limits: close duplicate TikTok tabs/apps, wait, then retry with another mode. +- Duplicates after reconnect: update app, stop the source fully, reconnect cleanly, and try another mode if it persists. +- Extension versus app mismatch: the app has the widest TikTok mode selection; the browser extension is closer to DOM page capture. + +## Escalation Rules + +Escalate when: -## Starter Notes +- Multiple users report the same TikTok failure after normal mode switching. +- A recent TikTok page/API change breaks previously working capture. +- App direct chat routes return consistent 403/auth/session errors for signed-in users. +- Duplicate gift/social events survive clean reconnect and current regression expectations. +- A support claim comes only from historical Discord data and has not been checked against current `connection-manager.js`. -Support data repeatedly identifies TikTok as fragile. Known themes include API changes, standard mode throttling when hidden/minimized, WebSocket mode tradeoffs, duplicate gift behavior, and live/user ID setup mistakes. +## Extraction Notes -## Planned Sections +Needs intense pass: -- Standard mode -- WebSocket mode -- Signing providers -- App connection manager -- Gift/social event handling -- Common failures and escalation -- Historical vs current behavior +- Exact mapping of app WebSocket events to SSN payload fields. +- Local signer request lifecycle and all fallback states. +- Current app UI mode names from `ssapp/renderer.js`/source setup UI. +- Regression test expectations converted into user-facing troubleshooting. diff --git a/docs/agents/08-platform-sources/twitch.md b/docs/agents/08-platform-sources/twitch.md index 635fafd79..529d5c335 100644 --- a/docs/agents/08-platform-sources/twitch.md +++ b/docs/agents/08-platform-sources/twitch.md @@ -1,6 +1,6 @@ # Twitch Source -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass. Usable for support and architecture orientation, not final field-level docs. ## Purpose @@ -8,22 +8,157 @@ Document Twitch capture, WebSocket/EventSub behavior, OAuth, chat sending, badge ## Source Anchors +- `social_stream/manifest.json` - `social_stream/sources/twitch.js` - `social_stream/sources/websocket/twitch.html` - `social_stream/sources/websocket/twitch.js` - `social_stream/providers/twitch/chatClient.js` -- `ssapp/resources/electron-twitch-handler.js` +- `social_stream/docs/event-reference.html` - `social_stream/tests/twitch-chatClient-subgift.test.js` +- `ssapp/resources/electron-twitch-handler.js` + +## Runtime Surfaces + +Twitch has two main capture paths: + +- Standard DOM capture through `sources/twitch.js`. +- WebSocket/EventSub and IRC-style chat through `sources/websocket/twitch.html`, `sources/websocket/twitch.js`, and `providers/twitch/chatClient.js`. + +The manifest injects `sources/twitch.js` for Twitch chat pages and includes hosted/local matches for `sources/websocket/twitch.html`. + +## Standard DOM Capture + +`sources/twitch.js` reads rendered Twitch chat DOM. + +Confirmed behavior: + +- It watches chat containers such as `.chat-list--other`, `.chat-list--default`, `.chat-room__content`, and later `#root`. +- It marks pre-existing chat rows as ignored to avoid replaying loaded history. +- It forwards payloads with `type: "twitch"`. +- Payload fields include `chatname`, `username`, `chatbadges`, `nameColor`, `chatmessage`, `chatimg`, `membership`, `subtitle`, `mod`, `vip`, `hasDonation`, `contentimg`, `highlightColor`, `textonly`, `initial`, and `reply`. +- It supports Twitch, FFZ, BTTV, and 7TV badge/emote paths where the DOM/settings expose them. +- Bits/Cheers populate `hasDonation` such as `500 bits` even when `data.event` may be empty in DOM mode. +- Reply context is added unless `settings.excludeReplyingTo` is enabled. +- Viewer counts use Social Stream's Twitch viewer proxy every 30 seconds when viewer/hype settings allow it. +- DOM fallback supports limited system events such as reward cards, gift/sub text, hype train community highlights, Stream Together knocks, and viewer updates. + +Support setup: + +- Open Twitch chat/popout with the extension enabled. +- Sign in when the user needs badge/member/moderation context that only appears for signed-in/broadcaster/moderator accounts. +- Use WebSocket/EventSub mode for full followers, raids, channel point redemptions, and reliable event support. + +## WebSocket/EventSub Capture + +`sources/websocket/twitch.js` is the richer Twitch integration. + +Confirmed behavior: + +- Uses Twitch API/EventSub WebSocket at `wss://eventsub.wss.twitch.tv/ws`. +- Creates EventSub subscriptions based on the authenticated user's permissions/scopes. +- Uses `providers/twitch/chatClient.js` as shared provider logic for chat normalization and tmi.js client behavior. +- Relays messages with `chrome.runtime.sendMessage`; app/preload mock messages can use `window.postMessage` for `SEND_MESSAGE`. +- Suppresses `viewer_update` relays unless `showviewercount` or `hypemode` is enabled. +- Handles reconnect and permission-error states. + +EventSub events documented/confirmed include: + +- `new_follower` +- `new_subscriber` +- `resub` +- `subscription_gift` +- `cheer` +- `reward` +- `raid` +- `viewer_update` +- `follower_update` +- `subscriber_update` +- `stream_online` +- `stream_offline` +- `ad_break`, `ad_request`, `ad_schedule` +- `hype_train` +- `user_banned` + +## OAuth And Standalone App Auth + +The standalone app handler `ssapp/resources/electron-twitch-handler.js`: + +- Uses loopback host `127.0.0.1`. +- Tries ports `8181` then `8080`. +- Uses callback path `/sources/websocket/twitch.html`. +- Builds a Twitch implicit OAuth URL at `https://id.twitch.tv/oauth2/authorize`. +- Opens the auth URL in the default browser. +- Extracts the access token from the callback landing page and posts it back to the local loopback server. +- Returns a port-conflict dialog if both ports are unavailable. + +Support implication: app sign-in failures can be simple loopback port conflicts, especially if another app already uses `8080`. + +## Scopes And Permissions + +`docs/event-reference.html` lists the broad Twitch WebSocket/EventSub scope set: + +- `chat:read` +- `chat:edit` +- `bits:read` +- `moderator:read:followers` +- `channel:read:subscriptions` +- `channel:read:hype_train` +- `channel:moderate` +- `moderator:manage:banned_users` +- `moderator:manage:chat_messages` +- `channel:read:redemptions` +- `channel:read:ads` +- `channel:manage:ads` + +Actual EventSub subscriptions are created only when permission checks allow them. For example, channel point redemption events require broadcaster-level access with redemption scope. + +## Chat Sending And Moderation + +Provider behavior from `providers/twitch/chatClient.js`: + +- `sendMessage(message, targetChannel)` requires a connected tmi.js client with `say()`. +- Missing channel throws `Channel is required to send a message`. +- Missing connected client throws `Twitch client is not connected`. +- Chat messages are normalized with `chatname`, `chatmessage`, `chatimg`, `timestamp`, `chatbadges`, `hasDonation`, `bits`, moderator/owner/subscriber flags, `userId`, `event`, and raw metadata. + +Delete/moderation behavior: + +- WebSocket Twitch has source-control delete paths that send `{ delete: ... }`. +- `user_banned` is metadata-only for moderation widgets. +- Custom overlays should process delete payloads before normal message-add rendering. + +## Event And Payload Notes + +Important mappings: + +- Regular chat should not set `data.event`; true system events do. +- `/me` action messages become an `action`-style event in provider normalization. +- Bits can be `event: "cheer"` or provider-normalized `bits` depending on path; downstream donation widgets should also check `hasDonation`. +- Gifted subs are normalized as `subscription_gift`. The test `tests/twitch-chatClient-subgift.test.js` confirms direct and anonymous gifted sub summaries: + - `THErealNEDRYERSON gifted a sub to abookwitch!` + - `Anonymous gifted a sub to quietviewer!` + +## Common Failures + +- Chat works but follows/raids/subs do not: user is likely in DOM mode or lacks EventSub scopes/permissions. +- EventSub auth expired: reconnect/sign in again; the source has status hooks for auth/API failures. +- Channel points missing: must be broadcaster-authorized with `channel:read:redemptions`. +- Subscriber totals missing: require broadcaster token and subscription access. +- OBS overlay does not update: verify session ID, refresh browser source, and confirm dock/source receives messages first. +- Replies look duplicated or noisy: check `excludeReplyingTo` and text-only settings. +- App OAuth fails: check loopback ports `8181` and `8080`. + +## App Vs Extension Differences -## Starter Notes +- Extension DOM mode reads the user's visible Twitch page. +- WebSocket/EventSub mode is closer to API/IRC and depends on OAuth scopes. +- Standalone app uses loopback OAuth and the app bridge; browser-login state alone may not be enough for app WebSocket features. -Twitch has classic source behavior plus newer WebSocket/EventSub paths and provider-core code. Support history mentions sign-in/auth loops on some versions. +## Extraction Notes -## Planned Sections +Needs intense pass: -- Standard capture -- WebSocket/EventSub capture -- OAuth -- Send/reply behavior -- Emotes and badges -- Common failures +- Exact Twitch WebSocket UI setup flow. +- All EventSub subscription gating rules. +- Full source-control command list for send/delete/ban/unban/ad/channel changes. +- Current Twitch OAuth token storage and refresh behavior. diff --git a/docs/agents/08-platform-sources/youtube.md b/docs/agents/08-platform-sources/youtube.md index 5f7f22a56..a66671b0c 100644 --- a/docs/agents/08-platform-sources/youtube.md +++ b/docs/agents/08-platform-sources/youtube.md @@ -1,33 +1,141 @@ # YouTube Source -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass. Usable for support and architecture orientation, not final field-level docs. ## Purpose -Document YouTube capture modes, setup, OAuth/API behavior, WebSocket/data API behavior, and support issues. +Document YouTube capture modes, setup, OAuth/API behavior, WebSocket/Data API behavior, message payloads, and common support issues. ## Source Anchors +- `social_stream/manifest.json` - `social_stream/sources/youtube.js` - `social_stream/sources/youtube_static.js` - `social_stream/sources/youtube_comments.js` - `social_stream/sources/websocket/youtube.html` - `social_stream/sources/websocket/youtube.js` -- `social_stream/providers/youtube/*` +- `social_stream/providers/youtube/liveChat.js` +- `social_stream/providers/youtube/contextResolver.js` +- `social_stream/docs/event-reference.html` +- `social_stream/docs/youtube-project-setup.html` +- `social_stream/docs/youtube-websocket-streaming-plan.md` - `ssapp/resources/electron-youtube-handler.js` - `ssapp/youtube.js` -- `social_stream/docs/youtube-project-setup.html` -## Starter Notes +## Runtime Surfaces + +YouTube has two main SSN capture paths: + +- Standard DOM capture through `sources/youtube.js`. +- WebSocket/Data API capture through `sources/websocket/youtube.html` and `sources/websocket/youtube.js`, with provider helpers in `providers/youtube/*`. + +The manifest injects `sources/youtube.js` on YouTube live chat URLs and includes content-script matches for the hosted/local `sources/websocket/youtube.html` page. The WebSocket/Data API page is also the OAuth callback path for standalone app loopback auth. + +## Standard DOM Capture + +Use standard capture when the user has an actual YouTube live chat page open. It reads rendered chat DOM and forwards `{ message: data }` to the extension runtime. + +Confirmed behavior: + +- `sources/youtube.js` processes `yt-live-chat-*` DOM elements and sends payloads with `type: "youtube"` or `type: "youtubeshorts"`. +- Chat payloads include fields such as `chatname`, `chatmessage`, `chatimg`, `chatbadges`, `nameColor`, `backgroundColor`, `textColor`, `membership`, `subtitle`, `hasDonation`, `donoValue`, `videoid`, `sourceName`, `sourceImg`, `textonly`, and `event`. +- When YouTube exposes a native live-chat element ID, the script adds `meta.messageId`; dock/source-control delete sync depends on this. +- Replies can be included as `initial` and `reply` unless `settings.excludeReplyingTo` is enabled. +- Super Chats, Super Stickers, YouTube Gifts/Jewels, memberships, gift purchases, gift redemptions, resubs, and redirect banners are detected from DOM cards when YouTube renders them. +- Viewer counts use `https://api.socialstream.ninja/youtube/viewers?video=VIDEO_ID` when `showviewercount` or `hypemode` is enabled. If the API quota path fails, the script can fall back to scraping the watch page and slows the polling interval. +- YouTube Shorts are detected from URL/query context and are sent as `type: "youtubeshorts"`. + +Support setup: + +- The user should open the live chat popout or supported Studio live chat view. +- The stream must be live for live-chat behavior to be meaningful. +- For a watch URL, the canonical form is usually `https://www.youtube.com/watch?v=VIDEO_ID`. +- If the user gives a video ID manually, the script can redirect to `https://www.youtube.com/live_chat?is_popout=1&v=VIDEO_ID`. + +## YouTube Studio Capture + +`sources/youtube.js` explicitly checks for `studio.youtube.com/live_chat` in stale-chat handling. Treat Studio chat as a supported DOM-capture surface, but do not assume all popout-only DOM cards are visible in Studio. Membership/gift cards depend on what YouTube renders for the signed-in account. + +## Stale Chat Recovery + +`sources/youtube.js` includes a stale DOM feed detector for live chat. The source comments document soak-test findings from 2026-05-24: + +- Reloading the live chat popout reliably restarted DOM/message flow. +- Trusted Electron wheel input also restarted the feed, but that is not currently used from `youtube.js` because it can steal focus. +- Synthetic page events, resize nudges, and component updates did not reliably restart the feed. + +Support implication: if YouTube chat stops after working, refreshing/reloading the chat popout is a source-backed workaround, not just generic advice. + +## WebSocket/Data API Capture + +The WebSocket/Data API path is the richer YouTube integration. + +Confirmed behavior: + +- `sources/websocket/youtube.js` relays page events such as `youtubeMessage`, `youtubeDelete`, `youtubeVideoChanged`, `youtubeEmojiRequest`, and `youtubeRichChatRequest`. +- It can send through `chrome.runtime.sendMessage` in the extension or through `window.ninjafy.sendMessage` in the standalone app. +- It listens for `SOURCE_CONTROL` and `SEND_MESSAGE` messages from the extension/app bridge. +- It requests settings from the background page and forwards settings changes to the source page through custom DOM events. +- `providers/youtube/liveChat.js` supports polling mode and streaming mode. Default polling interval is 4000 ms; the streaming endpoint is `https://www.googleapis.com/youtube/v3/liveChat/messages:stream`. +- Provider events include status, chat, membership, Super Chat, Super Sticker, sponsor, ban, delete message, metric, error, and debug. + +Event-reference notes: + +- WebSocket/Data API mode is required for broader YouTube event support such as API membership/subscriber events. +- New subscriber alerts use the `myRecentSubscribers` API, can be delayed by up to 4 hours, and only include public subscriptions. +- Redirect banners are not exposed by the YouTube Data API; `redirect` remains standard DOM only. +- Optional write access uses `youtube.force-ssl`, which Google may present broadly because YouTube does not expose a chat-only write scope. + +## OAuth And Standalone App Auth + +The standalone app handler `ssapp/resources/electron-youtube-handler.js`: + +- Uses loopback host `127.0.0.1`. +- Tries ports `8181` then `8080`. +- Uses callback path `/sources/websocket/youtube.html`. +- Supports hosted auth through `https://ytauth.socialstream.ninja/auth`. +- Supports custom Google OAuth mode through `https://accounts.google.com/o/oauth2/v2/auth`. +- Requests offline access and `prompt=consent` for custom Google mode. +- Opens the auth URL in the default browser. +- Returns an explicit port-conflict dialog when both loopback ports are unavailable. + +Support implication: if YouTube sign-in fails in the standalone app, check whether ports `8181` or `8080` are already in use. Streamer.bot commonly uses port `8080`. + +## Event And Payload Notes + +Important event names from `docs/event-reference.html`: + +- Standard DOM: `sponsorship`, `giftpurchase`, `giftredemption`, `resub`, `jeweldonation`, `donation`, `thankyou`, `redirect`, `viewer_update`. +- WebSocket/Data API: `donation`, `supersticker`, `jeweldonation`, `sponsorship`, `resub`, `giftpurchase`, `giftredemption`, `membermilestone`, `viewer_update`, `subscriber_update`, `view_update`, `live_chat_ended`, `user_banned`, `new_follower`. + +Cross-platform note: + +- YouTube uses `sponsorship` for new members. Twitch and Kick use `new_subscriber`. +- YouTube gift events use `giftpurchase` and `giftredemption`, not Twitch/Kick `subscription_gift`. +- Donation-like events are often signaled by `hasDonation`, even when the event name differs. + +## Common Failures + +- No messages: verify the extension/app is on, the correct live chat popout or Studio chat is open, and the stream is live. +- Wrong URL: convert watch URLs to `watch?v=VIDEO_ID` or popout chat URLs; stale or ended stream URLs are a common cause. +- Dock sees messages but overlay does not: check session ID and refresh the OBS browser source. +- Viewer count missing: ensure `showviewercount` or `hypemode` is enabled. +- Membership/gift cards missing: YouTube may not render these for the current account; broadcaster/moderator auth can matter. +- Subscriber alerts late/missing: YouTube API limitation. Up to 4-hour delay and private subscriptions do not appear. +- App OAuth fails: check port conflicts on `8181` and `8080`. +- Chat stalls after working: reload the live chat popout; the source has a stale-feed reload path for this exact symptom. + +## App Vs Extension Differences + +- Extension standard mode runs in the user's Chrome session and can see whatever YouTube renders there. +- Standalone app OAuth opens the default browser for loopback auth but the app still has Electron-specific bridge behavior. +- The WebSocket page can relay through Chrome runtime or `window.ninjafy`; failures can be bridge-specific. -Existing support guidance mentions pop-out chat, YouTube Studio behavior, correct `/watch?v=` URLs, auto-select live chat settings, and YouTube WebSocket/Data API modes. +## Extraction Notes -## Planned Sections +Needs intense pass: -- Standard capture -- YouTube Studio capture -- WebSocket/Data API capture -- OAuth and custom credentials -- Reply/send behavior -- Common failures -- App vs extension differences +- Exact OAuth scopes and UI labels in `sources/websocket/youtube.html`. +- Exact field mapping for every YouTube API message type. +- Send/delete/ban/moderation behavior through `SOURCE_CONTROL`. +- Current public setup docs cross-check against `youtube-project-setup.html`. diff --git a/docs/agents/09-api-and-integrations/ai-features.md b/docs/agents/09-api-and-integrations/ai-features.md index f67f0574d..a2342a982 100644 --- a/docs/agents/09-api-and-integrations/ai-features.md +++ b/docs/agents/09-api-and-integrations/ai-features.md @@ -1,34 +1,214 @@ # AI Features -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started from `docs/commands.html`, `ai.md`, `background.js`, shared AI files, and AI page inventory. -## Purpose +## Source Anchors -Document SSN AI/cohost/chatbot features and how they connect to live chat. +- `docs/commands.html` +- `ai.md` +- `ai.js` +- `background.js` +- `aiprompt.html` +- `aioverlay.html` +- `bot.html` +- `chatbot.html` +- `cohost.html` +- `cohost-overlay.html` +- `shared/ai/*` +- `shared/aiPrompt/overlayStore.js` +- `scripts/playwright-ai*.cjs` +- `tests/rag-*.test.js` -## Source Anchors +## What AI Covers + +SSN AI features include: + +- Public chat bot replies. +- Private one-on-one chatbot page. +- AI moderation/censor behavior. +- RAG/document-backed answers. +- Chat summaries. +- AI translation/processing paths. +- AI cohost pages and overlays. +- Local browser/runtime models. +- Hosted API providers. +- Optional TTS for AI replies. + +Use this as a feature map. For exact current menu labels and models, check `docs/commands.html`, settings definitions, and `background.js`. + +## Bot Surfaces + +| Surface | Role | +| --- | --- | +| `bot.html` | Main bot overlay/page with optional public chat responses and TTS. | +| `chatbot.html` | Dedicated private one-on-one chatbot page; command docs say it does not share the main bot's RAG dataset or chat history. | +| `cohost.html` | Multimodal AI cohost page. | +| `cohost-overlay.html` | Output/overlay surface for cohost behavior. | +| `aiprompt.html` | AI prompt/testing/configuration surface. | +| `aioverlay.html` | AI output overlay surface. | +| Background processing | Censor bot, LLM processing, RAG file handling, summaries, provider tests, and chat routing. | + +Support rule: if AI appears to "do nothing", confirm the relevant page is open and the relevant background setting is enabled before debugging the provider. + +## Provider Families + +Command docs list these provider families: + +| Provider Family | Cost/Runtime Boundary | Notes | +| --- | --- | --- | +| Ollama | Free/self-hosted local runtime | Uses Ollama native API, normally `http://localhost:11434`. | +| Local browser models | Local/browser runtime and hosted model assets | Current docs mention local Gemma/Qwen style browser assets. | +| OpenAI / ChatGPT | Provider API account/key/billing | Includes chat and realtime/voice model paths in docs. | +| Google Gemini | Provider API account/key/billing | Includes text and live multimodal options in docs. | +| DeepSeek | Provider API account/key/billing | Conversational provider option. | +| xAI / Grok | Provider API account/key/billing | Docs mention realtime voice sessions with ephemeral secrets. | +| AWS Bedrock | Cloud provider credentials/billing | Enterprise provider family. | +| OpenRouter | Provider/API account/key/billing | Unified multi-model API. | +| Groq | Provider/API account/key/billing | Low-latency OpenAI-compatible chat inference. | +| Custom API | User-hosted or third-party OpenAI-compatible endpoint | For llama.cpp, LM Studio, vLLM, and similar servers. | + +Important distinction from command docs: Ollama uses its own native API. For llama.cpp, LM Studio, vLLM, or other OpenAI-compatible servers, choose Custom API. + +## Ollama Setup Notes + +`ai.md` gives a basic local Llama/Ollama setup: + +- Install Ollama. +- Pull/run a model such as Llama. +- Ollama is normally available at `http://localhost:11434`. +- Browser extension use can hit CORS issues unless Ollama is configured to allow extension/browser origins. +- Standalone app may be less constrained, but `ai.md` still suggests setting `OLLAMA_ORIGINS` when needed. + +Support checks: + +- Is Ollama running? +- Does `http://localhost:11434` respond locally? +- Is the selected model installed? +- Did the user configure CORS/origins for extension use? +- Did the user choose Ollama, not Custom API, in SSN? + +## Custom API Notes + +Use Custom API for OpenAI-compatible servers such as: + +- llama.cpp server +- LM Studio +- vLLM +- Local or private OpenAI-compatible gateways + +Collect: + +- Endpoint URL. +- Model ID. +- Optional API key. +- Whether the endpoint permits browser/extension requests. +- Whether the standalone app or extension is being used. + +## RAG And Documents + +Command docs describe RAG as Retrieval-Augmented Generation for custom knowledge-base answers. `background.js` includes commands for uploading and deleting RAG files and returns `documentsRAG` with settings/popup state. + +Agent guidance: + +- RAG answers depend on uploaded documents and selected bot surface. +- Private `chatbot.html` can have separate chat/RAG behavior from the main bot according to command docs. +- Do not assume a document is loaded just because RAG is enabled. +- For stale/wrong answers, ask what files were uploaded and whether the correct bot/page is being used. + +## AI Moderation/Censor + +Command docs mention content moderation with non-blocking or strict blocking modes. Background code has LLM censor paths around incoming messages. + +Support guidance: + +- If messages disappear unexpectedly, check AI censor/moderation settings as well as normal filters. +- Strict/blocking modes can prevent messages from reaching overlays. +- Provider latency or failures may affect moderation timing. +- For high-risk broadcasts, test moderation behavior before live use. + +## Chat Bot Replies + +Chat bot behavior can involve: + +- Enabling the LLM AI chat bot. +- Selecting provider/model. +- Setting bot name/trigger words. +- Setting response rate limits. +- Choosing whether replies go back to chat or only to bot/overlay pages. +- Enabling TTS for bot replies. +- Routing bot replies to selected source accounts/roles where configured. + +Support checks: + +- Can the selected provider pass the built-in test? +- Is the chat bot enabled, not just the provider configured? +- Does the source platform allow sending chat? +- Is the user signed in and permitted to send messages? +- Is the response rate limited? +- Are bot trigger words too restrictive? + +## AI Cohost + +Command docs describe the cohost as a multimodal AI that can see screen, hear audio, and interact. `background.js` includes cohost overlay labels, tool status, and cohost tool request/response routing. + +Support checks: + +- Is `cohost.html` open? +- Is `cohost-overlay.html` open when visual/audio output is expected? +- Is the overlay label correct? Code defaults include labels such as `cohost-overlay` and `ai-overlay`. +- Is the selected provider capable of the requested multimodal mode? +- Are microphone/screen/media permissions available in the active browser/app context? + +## TTS With AI + +AI replies can be paired with TTS. Use the TTS doc for provider details. + +Common issue: the LLM reply appears in text but no audio plays. Check: + +- TTS provider enabled. +- TTS-producing page open. +- Browser audio gate/OBS audio capture. +- Provider key/model/voice. +- Whether TTS is disabled or queue cleared. + +## Free vs Paid Boundaries + +Free/local: + +- Ollama and local models can be free software paths but require user hardware. +- Browser local models can be free but may require model assets, memory, GPU/WASM support, and time. + +Paid/provider: + +- OpenAI, Gemini, DeepSeek, xAI, Groq, OpenRouter, Bedrock, and similar cloud APIs depend on provider accounts, keys, quotas, and billing. + +Do not frame cloud AI as included/free with SSN. SSN supports the integration; the provider controls pricing and access. + +## Common Failures + +| Symptom | Likely Cause | First Checks | +| --- | --- | --- | +| Provider test fails | Bad key/endpoint/model/CORS | Use built-in provider test; check endpoint from same surface. | +| Ollama works in app but not extension | CORS/origin issue | Configure `OLLAMA_ORIGINS`; restart Ollama/browser. | +| Bot does not reply | Bot disabled, trigger mismatch, rate limit, source cannot send | Enable bot, test provider, send manual chat, check triggers. | +| Messages vanish | AI censor strict/blocking mode | Disable moderation temporarily; check filters. | +| RAG answer ignores docs | Wrong bot/page or no documents loaded | Check uploaded docs and RAG setting. | +| Cohost overlay silent/blank | Overlay page/label missing | Open `cohost-overlay.html`; check target label/status. | +| Local browser model slow | Hardware/runtime/model size | Use smaller model or hosted provider. | +| API key appears in URL/screenshot | Secret exposure | Rotate key if public; avoid sharing URLs with keys. | + +## Safety Notes + +- AI replies are generated content and can be wrong, unsafe, or off-brand. +- Use custom instructions and moderation, but do not treat them as guarantees. +- Test in a private session before live public replies. +- Rate-limit bot responses to avoid platform spam or account restrictions. +- Avoid sending private chat or sensitive viewer data to cloud providers unless the user understands the privacy boundary. + +## Follow-Up Extraction Needs -- `social_stream/ai.js` -- `social_stream/ai.md` -- `social_stream/aiprompt.html` -- `social_stream/aioverlay.html` -- `social_stream/cohost.html` -- `social_stream/cohost-overlay.html` -- `social_stream/chatbot.html` -- `social_stream/shared/ai/*` -- `social_stream/scripts/playwright-ai*.cjs` -- `social_stream/tests/rag-*.test.js` - -## Starter Notes - -AI features include self-hosted or provider-backed bot behavior, cohost overlays, local browser models, prompt pages, RAG tests, and live chat monitoring/response modes. - -## Planned Sections - -- AI settings -- Provider choices -- Local browser model assets -- Cohost overlay -- Chatbot/live response mode -- Safety and moderation -- Tests and limitations +- Exact current popup setting names and storage keys for AI features. +- Provider-by-provider request/response behavior from `ai.js` and background helpers. +- RAG file format/size/embedding behavior. +- Current cohost tool list and permission model. +- Summaries from Playwright AI and RAG tests. diff --git a/docs/agents/09-api-and-integrations/event-flow-editor.md b/docs/agents/09-api-and-integrations/event-flow-editor.md index 611c8aa4c..89509414c 100644 --- a/docs/agents/09-api-and-integrations/event-flow-editor.md +++ b/docs/agents/09-api-and-integrations/event-flow-editor.md @@ -1,10 +1,10 @@ # Event Flow Editor -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started on 2026-06-24. ## Purpose -Document the Event Flow Editor, triggers, actions, state nodes, tests, and common use cases. +Event Flow is SSN's visual automation layer. It lets users connect source triggers, logic gates, state nodes, and actions so chat messages or system events can be filtered, modified, relayed, displayed, spoken, or sent to integrations. ## Source Anchors @@ -13,20 +13,366 @@ Document the Event Flow Editor, triggers, actions, state nodes, tests, and commo - `social_stream/actions/event-flow-guide.html` - `social_stream/actions/state-nodes-guide.html` - `social_stream/actions/STATE_NODES_EXPLANATION.md` +- `social_stream/actions/examples/kick-channel-points-action-flow.json` - `social_stream/docs/kick-channel-points-event-flow.md` -- `social_stream/tests/eventflow-*.test.js` +- `social_stream/tests/eventflow-customjs.test.js` +- `social_stream/tests/eventflow-compare-property.test.js` +- `social_stream/tests/eventflow-template-vars.test.js` +- `social_stream/tests/eventflow-play-media-duration.test.js` -## Starter Notes +## Mental Model -The Event Flow system is a visual automation layer. It should be documented with exact trigger/action names from source, not guessed UI labels. +An Event Flow is a graph. A source event enters a trigger node, passes through optional logic or state nodes, then reaches one or more actions. -## Planned Sections +Each line carries: -- Editor concepts -- Triggers -- Actions -- State nodes -- Custom JS -- Media and OBS actions -- Kick rewards example -- Testing and troubleshooting +- A message/event payload. +- A boolean gate value. + +If a node returns `true`, downstream nodes continue. If it returns `false`, downstream nodes stop for that branch. Some actions modify the payload and continue; others block, relay, display, or run side effects. + +Do not put arbitrary custom data at the top level unless current code expects it. Existing docs point agents toward `docs/event-reference.html` for canonical fields and recommend putting extra custom data inside `meta`. + +## User Entry Points + +- Event Flow editor page: `actions/` in the web repo. +- Event Flow guide: `actions/event-flow-guide.html`. +- State node guide: `actions/state-nodes-guide.html`. +- Flow Actions overlay: `actions.html?session=YOUR_SESSION`. + +Media, audio, text overlay, and OBS actions need a rendering/control surface. In normal streaming use, that surface is the Flow Actions overlay running as a browser tab or OBS Browser Source. If the overlay is closed, those actions can appear to do nothing even though the flow itself is firing. + +## Trigger Families + +Exact trigger IDs come from `actions/EventFlowEditor.js`. + +Stream events: + +- `eventNewFollower` +- `eventNewSubscriber` +- `eventResub` +- `eventGiftSub` +- `eventDonation` +- `eventRaid` +- `eventCheer` +- `eventOther` +- `eventCustom` + +OBS Studio system events: + +- `obsStreamStarted` +- `obsStreamStopped` +- `obsRecordingStarted` +- `obsRecordingStopped` +- `obsSceneChanged` +- `obsReplaybufferSaved` + +OBS events are non-chat payloads with `type: "obs"` and an `event` value such as `stream_started`, `recording_started`, `scene_changed`, or `replay_buffer_saved`. Tests confirm they are allowed into Event Flow but do not trigger `anyMessage`. + +Chat message triggers: + +- `anyMessage` +- `messageContains` +- `messageStartsWith` +- `messageEndsWith` +- `messageEquals` +- `messageRegex` + +Message property triggers: + +- `messageLength` +- `wordCount` +- `containsEmoji` +- `containsLink` +- `hasDonation` +- `compareProperty` +- `messageProperties` + +User and source triggers: + +- `fromSource` +- `fromChannelName` +- `fromUser` +- `userRole` +- `channelPointRedemption` + +Timing and random triggers: + +- `randomChance` +- `timeInterval` +- `timeOfDay` + +MIDI triggers: + +- `midiNoteOn` +- `midiNoteOff` +- `midiCC` + +Advanced triggers: + +- `eventType` +- `customJs` + +## Action Families + +Message actions: + +- `blockMessage` +- `returnMessage` +- `continueAsync` +- `modifyMessage` +- `addPrefix` +- `addSuffix` +- `findReplace` +- `removeText` +- `setProperty` +- `featureMessage` +- `sendMessage` +- `relay` +- `reflectionFilter` + +Integration actions: + +- `customJs` +- `webhook` +- `addPoints` +- `spendPoints` + +Media and effects actions: + +- `playTenorGiphy` +- `showAvatar` +- `showText` +- `clearLayer` +- `playAudioClip` +- `delay` + +OBS Studio actions: + +- `obsChangeScene` +- `obsToggleSource` +- `obsSetSourceFilter` +- `obsMuteSource` +- `obsStartRecording` +- `obsStopRecording` +- `obsStartStreaming` +- `obsStopStreaming` +- `obsReplayBuffer` + +Spotify actions: + +- `spotifySkip` +- `spotifyPrevious` +- `spotifyPause` +- `spotifyResume` +- `spotifyToggle` +- `spotifyVolume` +- `spotifyQueue` +- `spotifyNowPlaying` +- `spotifyShuffle` +- `spotifyRepeat` + +TTS actions: + +- `ttsSpeak` +- `ttsToggle` +- `ttsSkip` +- `ttsClear` +- `ttsVolume` + +MIDI actions: + +- `midiSendNote` +- `midiSendCC` + +State control actions: + +- `setGateState` +- `resetStateNode` +- `setCounter` +- `incrementCounter` +- `checkCounter` + +## Logic Nodes + +Current logic node types: + +- `AND` +- `OR` +- `NOT` +- `RANDOM` +- `CHECK_BAD_WORDS` + +The user-facing guide also describes common filter patterns such as compare, regex, condition, and reflection/no-echo protection. In support answers, be careful to distinguish actual node IDs from broader guide concepts. + +## State Nodes + +Current state node types: + +- `GATE`: on/off switch that can allow or block downstream flow. +- `COUNTER`: count-based state for thresholds and cooldown-like workflows. +- `THROTTLE`: rate limiter. + +Common setup rule: add the state node first, give it a stable name or ID, then point the matching action node at that state node. If an action references the wrong node ID/name, it has nothing useful to update. + +State actions: + +- `setGateState`: changes a gate to allow/block. +- `resetStateNode`: resets a target state node. +- `setCounter`: sets a counter value. +- `incrementCounter`: increments a counter value. +- `checkCounter`: copies counter details onto the message for later templates. + +Tests confirm `checkCounter` exposes: + +- `counterValue` +- `counterTarget` +- `counterRemaining` + +Example template: + +```text +You have to wait {counterRemaining} seconds to send a tts! +``` + +## Template Variables + +Templates can use common SSN payload fields such as: + +- `{username}` +- `{message}` +- `{source}` +- `{chatname}` +- `{chatmessage}` +- `{hasDonation}` +- `{membership}` +- `{meta}` + +Tests also verify dynamic top-level fields can render in templates. For counters, `counterRemaining` is derived from `counterTarget - counterValue`. + +## Custom JS + +Custom JS exists as both a trigger (`customJs`) and an action (`customJs`). + +Important runtime boundary: + +- In the Chrome extension context, custom JS eval is disabled because MV3 extension pages do not allow dynamic eval under the default CSP. +- In SSApp/Electron-like contexts, custom JS eval is allowed. + +Current detection treats these as allow contexts: + +- `window.ssapp === true` +- `window.ninjafy` truthy +- `window.electronApi` truthy +- URL has `?ssapp` +- global `isSSAPP === true` +- explicit constructor option `allowEvalCustomJs: true` + +Tests confirm blocked custom JS triggers return `false`, and blocked custom JS actions do not execute user code. When allowed, custom JS triggers can return a boolean, and custom JS actions can mutate the message and return a result object. + +Support guidance: + +- If a custom-code node works in SSApp but not in the Chrome extension, that is expected unless the extension CSP/runtime is changed. +- Syntax errors in custom JS should fail the node, not crash the full flow. +- Do not recommend unsafe eval changes casually; prefer SSApp/Electron for custom code workflows. + +## Media And Overlay Actions + +`playAudioClip`, `playTenorGiphy`, and `showText` send payloads to the Flow Actions overlay. The overlay should be open at: + +```text +actions.html?session=YOUR_SESSION +``` + +Recommended OBS setup from the guide: + +- Add it as an OBS Browser Source when the output should render on stream. +- Use a 1920x1080 browser source unless the user has a specific canvas/layout reason to do otherwise. +- Keep the overlay open while the flow should produce audio/media/text effects. + +`playTenorGiphy` duration behavior from tests: + +- Undefined duration falls back to `10000` ms. +- Explicit `duration: 0` is preserved and means manual close behavior for that overlay payload. + +## OBS Actions + +OBS controls can work in two modes: + +- Browser Source API: only when `actions.html` runs inside an OBS Browser Source with the right advanced access. +- OBS WebSocket: recommended mode for source/filter/mute/scene/recording/streaming actions. + +OBS WebSocket requirements in current docs: + +- OBS 28+. +- obs-websocket v5 API. +- Default port `4455`. +- Example: `actions.html?session=test&obsws=ws://127.0.0.1:4455`. +- Add `&obspw=...` only if the OBS WebSocket server is configured to require a password. +- Add `&obsdebug=1` to show a small diagnostic badge on the overlay. + +Old obs-websocket 4.x on port `4444` is not expected to work for source/filter/mute controls until the user upgrades. + +## Kick Reward Example + +The current example flow is `actions/examples/kick-channel-points-action-flow.json`, with detailed instructions in `docs/kick-channel-points-event-flow.md`. + +The example uses: + +- Trigger `channelPointRedemption` with `rewardName`. +- Trigger `fromSource` with `source: "kick"`. +- Logic `AND`. +- Actions `playAudioClip`, `playTenorGiphy`, and `showText`. + +Key support point: Kick channel rewards should use the Kick bridge source, not only the ordinary Kick chatroom. The bridge can emit structured reward events with `type: "kick"`, `event: "reward"`, and reward details in `meta`. + +## Relay Loop Protection + +The guide describes No Reflections / No Echo behavior for relay workflows. When building relay flows, tag relayed messages in `meta` where possible, for example `meta.source = "relay"`, and add a reflection/no-echo filter before re-relaying. + +Without loop protection, a flow can relay a message into another destination, then capture its own relayed message and repeat. + +## Troubleshooting + +Flow does not fire: + +- Confirm the flow is saved and active. +- Confirm the source tab/bridge is open and sending events. +- Use the Event Flow test panel with a payload that actually matches the trigger. +- For reward-name filters, the test message or event must include the reward name. +- For OBS events, use OBS-specific triggers, not `anyMessage`. + +Media/audio/text action does nothing: + +- Open the Flow Actions overlay with the same session. +- Check browser/OBS source audio permissions. +- Confirm the media/audio URL is reachable. +- For OBS Browser Source usage, verify the overlay is actually loaded in OBS. + +OBS action does nothing: + +- Prefer OBS WebSocket v5 on port `4455`. +- Add `&obsws=ws://127.0.0.1:4455` to the overlay URL. +- Add `&obspw=...` only if OBS requires auth. +- Use `obs-websocket-test.html` for connection testing. +- Upgrade if the user is on obs-websocket 4.x / port `4444`. + +State action seems broken: + +- Confirm the state node exists. +- Confirm action target node ID/name matches the state node. +- Reset state between tests when old state could be affecting results. +- For counters, use `checkCounter` before trying to render `{counterRemaining}`. + +Custom JS does not run: + +- In the Chrome extension, this is expected because eval is disabled by CSP. +- Use SSApp/Electron or an approved runtime path for custom JS workflows. +- Check the console for syntax/runtime errors. + +## Remaining Extraction Targets + +- Line-level review of every trigger evaluator in `EventFlowSystem.js`. +- Line-level review of every action executor, especially relay, webhook, points, Spotify, TTS, MIDI, and OBS actions. +- Cross-check `STATE_NODES_EXPLANATION.md` against current code because some older notes appear stale compared with current editor/test behavior. +- Add support-derived examples for common automation recipes. diff --git a/docs/agents/09-api-and-integrations/index.md b/docs/agents/09-api-and-integrations/index.md index d008a820e..a86696c9b 100644 --- a/docs/agents/09-api-and-integrations/index.md +++ b/docs/agents/09-api-and-integrations/index.md @@ -1,6 +1,6 @@ # API And Integrations Index -Status: framework only. Detailed extraction not started. +Status: framework plus WebSocket/HTTP API, TTS, AI, OBS, StreamDeck/Companion, Streamer.bot, and Event Flow heavy passes. ## Purpose @@ -8,10 +8,18 @@ This section covers external APIs, automation, OBS, StreamDeck, Companion, Strea ## Pages -- `websocket-http-api.md` -- `obs.md` -- `streamdeck-companion.md` -- `streamerbot.md` -- `event-flow-editor.md` -- `tts.md` -- `ai-features.md` +- `websocket-http-api.md`: heavy extraction pass started. +- `obs.md`: heavy extraction pass started. +- `streamdeck-companion.md`: heavy extraction pass started. +- `streamerbot.md`: heavy extraction pass started. +- `event-flow-editor.md`: heavy extraction pass started. +- `tts.md`: heavy extraction pass started. +- `ai-features.md`: heavy extraction pass started. + +## Suggested Next Pass + +- Intense extraction for `event-flow-editor.md` using line-level trigger/action execution paths in `EventFlowSystem.js`. +- Intense extraction for `streamerbot.md` by tracing the exact background WebSocket/DoAction request path. +- Intense extraction for `tts.md` provider behavior from `tts.js`. +- Intense extraction for `ai-features.md` provider/RAG/cohost behavior from `ai.js`, `background.js`, and tests. +- Intense pass on API command behavior by tracing `background.js`, `dock.html`, and special pages. diff --git a/docs/agents/09-api-and-integrations/obs.md b/docs/agents/09-api-and-integrations/obs.md index 21137c8d3..e5329289e 100644 --- a/docs/agents/09-api-and-integrations/obs.md +++ b/docs/agents/09-api-and-integrations/obs.md @@ -1,30 +1,162 @@ # OBS Integration -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started from README, `parameters.md`, `api.md`, Event Flow guide, and OBS tester. -## Purpose +## Source Anchors -Document using SSN with OBS browser sources, window capture, OBS WebSocket, and common overlay display issues. +- `README.md` +- `parameters.md` +- `api.md` +- `dock.html` +- `featured.html` +- `actions.html` +- `actions/event-flow-guide.html` +- `actions/EventFlowEditor.js` +- `obs-websocket-test.html` +- `thirdparty/obs-websocket.min.js` -## Source Anchors +## Main OBS Workflows + +| Workflow | SSN Surface | Notes | +| --- | --- | --- | +| Show selected chat | `featured.html` Browser Source | Most common stream overlay path. | +| Operate chat | `dock.html` browser/custom dock/window | Use as operator UI, not usually public output. | +| Style an overlay | OBS Browser Source custom CSS or URL params | Fastest safe customization path. | +| Read TTS audio | Browser Source audio or system audio routing | Provider TTS captures better than system TTS. | +| Event Flow media/actions | `actions.html` Browser Source | Must stay open for overlay/audio/OBS actions. | +| OBS scene/source control | Browser Source API or OBS WebSocket v5 | Permissions and WebSocket version matter. | + +## Browser Source Setup + +Common URLs: + +```text +https://socialstream.ninja/featured.html?session=SESSION_ID +https://socialstream.ninja/dock.html?session=SESSION_ID +https://socialstream.ninja/actions.html?session=SESSION_ID +``` + +Common sizes: + +- Featured/basic overlay: `1280x600` or `1920x600` from README guidance. +- Full-canvas themed overlays or Event Flow Actions: `1920x1080` is often appropriate. + +Support checks: + +- Session ID matches extension/app/source. +- Browser Source URL includes `session`. +- Source is refreshed after URL/CSS changes. +- Browser Source is visible on the active scene. +- CSS is not hiding text or setting same foreground/background colors. + +## Dock vs Featured + +- `dock.html`: operator dashboard and control UI. +- `featured.html`: public selected-message overlay. +- `actions.html`: Event Flow output/action surface. + +Common user confusion: opening `dock.html` and expecting only a clean featured overlay, or opening `featured.html` and thinking it is broken because it is transparent/blank until a message is selected. + +## Styling In OBS + +Recommended styling paths: + +- Use URL parameters from `parameters.md`. +- Use OBS Browser Source custom CSS. +- Use `css` or `cssb64` parameters. +- Use `themes/featured-styles/*` for purpose-built featured overlays. + +README warns that local self-hosted dock/featured files can be problematic in OBS on macOS/Linux. Hosted `socialstream.ninja` pages or OBS CSS are safer there. + +## TTS Audio + +TTS capture rule: + +- Browser/provider TTS such as Kokoro, Google Cloud, ElevenLabs, Speechify, OpenAI-compatible provider paths generally play inside the browser page and work better with OBS Browser Source audio control. +- Free system/Web Speech TTS can play through the OS default output and may require virtual cable, application audio capture, or desktop audio capture. + +If users say "TTS works but OBS does not hear it", first identify which TTS provider/mode they use. + +## OBS Remote Scene Support + +README says OBS remote scene/stats support requires adding an SSN page to OBS as a Browser Source with appropriate page permissions. An OBS custom dock is not enough for the required permissions. + +Parameters from `parameters.md`: + +| Parameter | Meaning | +| --- | --- | +| `remote` | Enables OBS scene state display/control integration. | +| `cycle` | Allows guests to change OBS scenes with `!cycle` when enabled. | +| `startstop` | Allows privileged users to start/stop streaming. | +| `notobs` | Disables OBS Studio detection. | + +Permission notes: + +- Reading scene state needs user-level permissions. +- Starting/stopping streaming requires higher/full permissions. +- Use this carefully; chat-triggered OBS control can affect live production. + +## Event Flow And OBS WebSocket + +`actions/event-flow-guide.html` documents two OBS control modes: + +| Mode | Requirement | Notes | +| --- | --- | --- | +| Browser Source API | `actions.html` running inside OBS Browser Source with Advanced Access Level | Scene switching works; some recording/streaming/replay actions may fall back to this. | +| OBS WebSocket | OBS 28+ integrated OBS WebSocket v5, usually `ws://127.0.0.1:4455` | Recommended for consistent control. | + +Other Event Flow OBS notes: + +- Only append `&obspw=...` if OBS WebSocket requires a password. +- Add `&obsdebug=1` to `actions.html` to show a small OBS connection badge while troubleshooting. +- Old obs-websocket 4.x / port `4444` setups are not compatible with current Flow Actions source/filter/mute behavior. +- Keep `actions.html` open; closing it pauses overlay/audio/OBS actions. + +Diagnostic page: + +```text +https://socialstream.ninja/obs-websocket-test.html +``` + +The tester is intended for OBS 28+ / WebSocket v5. It can check `GetVersion`, `GetCurrentProgramScene`, `GetSceneList`, scene switching, source visibility, filters, mute, record, stream, and replay buffer actions. + +## API/Automation With OBS + +StreamDeck/Companion/API actions can indirectly affect OBS output by controlling SSN: + +- `clearOverlay` +- `nextInQueue` +- `autoShow` +- `feature` +- `content` +- `toggleTTS` + +Event Flow can directly control OBS scenes/sources/filters where permissions or WebSocket are configured. + +## Common Support Issues -- `social_stream/README.md` -- `social_stream/dock.html` -- `social_stream/featured.html` -- `social_stream/obs-websocket-test.html` -- `social_stream/api.md` -- `stevesbot/resources/learnings/playbooks/playbook-obs-overlay-issues.md` +| Symptom | Likely Cause | First Checks | +| --- | --- | --- | +| OBS overlay blank | No featured message, wrong URL/session, source hidden | Feature a test message; compare session; refresh source. | +| Page is white in browser | Transparent/empty overlay outside OBS | Use dock to feature a message; check CSS/background. | +| Text cropped | Browser Source too short or CSS too large | Use `1280x600`/`1920x600`; adjust scale/CSS. | +| CSS not applying | CSS specificity or local-file issue | Use OBS CSS field; add `!important`; avoid local files on macOS/Linux. | +| TTS silent in OBS | System TTS not captured | Use provider/browser TTS or route system audio. | +| OBS scene commands fail | Wrong permission/control mode | Use Browser Source Advanced Access or OBS WebSocket v5. | +| OBS WebSocket fails | Wrong port/version/password or mixed content | Use `4455`, OBS 28+, correct password; test with `obs-websocket-test.html`. | +| Event Flow actions stop | `actions.html` closed/not visible/running | Keep the actions overlay open. | +| `!cycle` does nothing | OBS remote/cycle not enabled or no permissions | Check `cycle`, OBS permissions, and source page context. | -## Starter Notes +## Safety Notes -OBS is a central workflow. Support issues often involve wrong URLs, missing session IDs, transparent pages appearing white in browsers, browser-source refreshes, and audio/TTS routing. +- Do not expose OBS WebSocket passwords in public URLs/screenshots. +- Be careful with chat-triggered scene/source/start-stop controls. +- Test OBS actions in a safe scene before live production. +- If a public chat can trigger actions, use filters/moderation/role restrictions. -## Planned Sections +## Follow-Up Extraction Needs -- Browser source setup -- Dock vs featured overlay -- Transparent backgrounds -- Recommended sizes -- OBS WebSocket control -- Audio/TTS routing -- Troubleshooting +- Exact OBS action list from `EventFlowEditor.js`. +- Screenshot-based OBS overlay troubleshooting guide. +- Browser Source permission matrix by OBS version. +- Mapping from `remote`, `cycle`, and `startstop` to exact code paths. diff --git a/docs/agents/09-api-and-integrations/streamdeck-companion.md b/docs/agents/09-api-and-integrations/streamdeck-companion.md index 2a32eb0d6..965621ea9 100644 --- a/docs/agents/09-api-and-integrations/streamdeck-companion.md +++ b/docs/agents/09-api-and-integrations/streamdeck-companion.md @@ -1,26 +1,193 @@ # StreamDeck And Bitfocus Companion -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started from `api.md`, `docs/commands.html`, and README MIDI/API sections. -## Purpose +## Source Anchors -Document StreamDeck and Bitfocus Companion control of SSN through API commands. +- `api.md` +- `docs/commands.html` +- `README.md` +- `parameters.md` +- `background.js` +- `dock.html` -## Source Anchors +## What This Integration Does + +StreamDeck and Bitfocus Companion can control SSN through the API server. Typical actions: + +- Clear featured overlay. +- Feature next message. +- Advance queue. +- Toggle auto-show. +- Send chat messages. +- Toggle TTS. +- Reset/close polls. +- Control waitlists. +- Trigger custom content. + +## Required SSN Toggle + +For remote control, enable: + +```text +Enable remote API control of extension +``` + +Public docs place this under Global settings > Mechanics. Remote-control examples use channel 1 by default. + +If the goal is to receive chat in another app, that is a different workflow and also requires `Send chat messages to API server`, then listening on channel 4. + +## StreamDeck HTTP Method + +Use StreamDeck's Website action with background GET request enabled. + +Format: + +```text +https://io.socialstream.ninja/SESSION_ID/ACTION/TARGET/VALUE +``` + +Examples: + +```text +https://io.socialstream.ninja/SESSION_ID/clearOverlay +https://io.socialstream.ninja/SESSION_ID/nextInQueue +https://io.socialstream.ninja/SESSION_ID/autoShow/null/toggle +https://io.socialstream.ninja/SESSION_ID/sendEncodedChat/null/Hello%20Stream +``` + +Use `sendEncodedChat` for StreamDeck buttons when text contains spaces or special characters. + +Test/generator page: + +```text +https://socialstream.ninja/sampleapi.html?session=SESSION_ID +``` + +## StreamDeck Multi-Actions + +Useful patterns: + +- Send a chat message, wait, then clear overlay. +- Trigger `nextInQueue`, wait, then toggle TTS. +- Send multiple API commands with delays to sequence a show segment. + +Advice: + +- Add short delays between commands if an overlay or queue action needs time. +- Keep messages URL-encoded. +- Test each button with a harmless session before using it live. + +## Bitfocus Companion + +Public docs point to Companion support for Social Stream Ninja: + +```text +https://bitfocus.io/companion +https://bitfocus.io/connections/socialstream-ninja +``` + +Basic setup: + +1. Enable remote API control in SSN. +2. Copy the SSN session ID. +3. Add/configure the Social Stream Ninja connection in Companion. +4. Paste the session ID into the module settings. +5. Test a simple action such as clear featured or next in queue. + +Common Companion actions documented: + +- Clear featured message. +- Clear all messages. +- Next in queue. +- Toggle auto-show. +- Feature next unfeatured. +- Reset poll. +- Close poll. +- Waitlist controls. +- TTS controls. +- Send chat message. + +Documented variable: + +- `queue_size` + +Older command docs mention variables such as current featured message/user. Verify current Companion module support before promising exact variable names beyond `queue_size`. + +## WebSocket Method + +For custom tooling or advanced Companion setups, use WebSocket: + +```javascript +const ws = new WebSocket("wss://io.socialstream.ninja/join/SESSION_ID"); + +ws.onopen = () => { + ws.send(JSON.stringify({ action: "nextInQueue" })); + ws.send(JSON.stringify({ action: "clearOverlay" })); +}; +``` + +Use channel 1 for normal remote control unless a specific page/workflow requires a different channel. + +## MIDI Hotkey Path + +README documents a separate MIDI hotkey option. It can be used with StreamDeck through a MIDI plugin and a virtual MIDI loopback device. + +Documented Control Change channel 1 examples: + +| Command | Value | Behavior | +| --- | --- | --- | +| 102 | 1 | Say `1` into all chats. | +| 102 | 2 | Say `LUL` into all chats. | +| 102 | 3 | Tell a random joke into all chats. | +| 102 | 4 | Clear featured chat overlays. | + +Support checks: + +- MIDI option enabled in SSN menu. +- MIDI loopback device installed/configured. +- StreamDeck MIDI plugin sends the expected CC/channel/value. + +## Common Command Map + +| Desired Button | Action | +| --- | --- | +| Clear featured overlay | `clearOverlay` | +| Feature next queued message | `nextInQueue` | +| Toggle automatic featuring | `autoShow` with value `toggle` | +| Send text to chat | `sendEncodedChat` | +| Clear dock messages | `clear` or `clearAll` | +| Feature next unfeatured message | `feature` | +| Toggle TTS | `toggleTTS` with value `toggle` | +| Get queue size | `getQueueSize` with callback-capable client | +| Reset poll | `resetpoll` | +| Close poll | `closepoll` | +| Select waitlist winner | `selectwinner` | + +Use `websocket-http-api.md` for the broader action catalog. + +## Common Failures -- `social_stream/api.md` -- `social_stream/popup.html` -- `social_stream/background.js` +| Symptom | Likely Cause | First Checks | +| --- | --- | --- | +| Button does nothing | API toggle off, wrong session, bad URL | Enable remote API; test `clearOverlay`; verify session. | +| Text truncates or special chars break | Message not URL-encoded | Use `sendEncodedChat` and encode spaces/symbols. | +| All docks respond | Missing target label | Add `&label=` to dock/featured and target it. | +| Companion cannot connect | Module/session/config issue | Re-paste session; test HTTP URL; check SSN toggle. | +| Queue size variable stale | No callback/client listener or module limitation | Test `getQueueSize`; verify Companion module support. | +| Chat send fails but overlay commands work | Source cannot send chat | Manually send in source page; check sign-in/permissions. | +| MIDI buttons fail | MIDI option or loopback not configured | Confirm CC channel/value and loopback device. | -## Starter Notes +## Safety Notes -Existing API docs include StreamDeck and Companion setup sections. This page should extract command examples, required settings, and troubleshooting. +- Keep session IDs private; a session ID can control overlays or inject content. +- Avoid StreamDeck buttons that spam chat. +- Use account/platform permissions carefully when sending chat via automation. +- Add delays in multi-actions to avoid flooding API commands. -## Planned Sections +## Follow-Up Extraction Needs -- Enable API server -- Choose channel/endpoint -- Common actions -- Variables -- Multi-action examples -- Failure checks +- Current Companion module variable/action list from the module source or installed package. +- UI screenshots for StreamDeck setup. +- Exact MIDI implementation path and current command list from background code. +- Command recipes for common show workflows. diff --git a/docs/agents/09-api-and-integrations/streamerbot.md b/docs/agents/09-api-and-integrations/streamerbot.md index 9cfdd96a6..28e2e98c3 100644 --- a/docs/agents/09-api-and-integrations/streamerbot.md +++ b/docs/agents/09-api-and-integrations/streamerbot.md @@ -1,10 +1,10 @@ # Streamer.bot Integration -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started on 2026-06-24. ## Purpose -Document Streamer.bot integration setup and troubleshooting. +SSN can send captured chat/events into Streamer.bot over Streamer.bot's WebSocket server. Streamer.bot then runs a chosen Action for each incoming SSN payload. ## Source Anchors @@ -13,14 +13,182 @@ Document Streamer.bot integration setup and troubleshooting. - `social_stream/background.js` - `social_stream/api.md` -## Starter Notes +## Integration Model -Popup settings include Streamer.bot WebSocket fields. Existing setup pages should be extracted before giving exact setup instructions. +The integration is outbound from SSN to Streamer.bot: -## Planned Sections +1. SSN captures and normalizes a platform message. +2. SSN connects to Streamer.bot's WebSocket server. +3. SSN sends a DoAction-style request to a configured Streamer.bot Action ID. +4. Streamer.bot exposes the SSN payload fields as action arguments. +5. The user's Streamer.bot action handles filtering, routing, logging, chat replies, OBS actions, sound alerts, or any other Streamer.bot side effects. -- Streamer.bot setup -- Required SSN settings -- Action IDs and WebSocket password -- Event routing -- Troubleshooting +This does not replace the SSN dock or overlays. It gives Streamer.bot access to SSN's normalized cross-platform message payloads. + +## Prerequisites + +- Streamer.bot installed locally. +- Streamer.bot WebSocket Server enabled and running. +- SSN standalone app or extension configured with the Streamer.bot WebSocket URL. +- A Streamer.bot Action created specifically to process Social Stream messages. + +The existing guide recommends Streamer.bot `v0.2.3` or newer and notes that `v1.0+` moved WebSocket server settings into the redesigned settings area. For current Streamer.bot UI locations, agents should verify against Streamer.bot's current docs before giving exact menu names. + +## Streamer.bot Setup + +1. In Streamer.bot, open the WebSocket Server settings. +2. Enable the server. +3. Enable auto-start if the user wants it to run whenever Streamer.bot launches. +4. Note the port. The common default is `8080`. +5. If Streamer.bot WebSocket authentication is enabled, note the password. +6. Start the server and confirm it is listening. + +Recommended local URL: + +```text +ws://127.0.0.1:8080 +``` + +Use `127.0.0.1` when SSN and Streamer.bot run on the same PC. + +## Required Streamer.bot Action + +The Streamer.bot Action is required. Without an Action ID, SSN can connect but has no target action to run. + +1. Open the Streamer.bot Actions tab. +2. Create an action such as `Process SocialStream Message`. +3. Right-click the action and copy the Action ID. +4. Paste that Action ID into SSN's Streamer.bot settings. +5. Add sub-actions in Streamer.bot to log, filter, route, reply, play sounds, or run other actions. + +For simple workflows, no C# is required. Incoming SSN fields are available directly as `%fieldname%` in Streamer.bot sub-actions that support arguments. + +Example direct message template: + +```text +[%originalPlatform%] %chatname%: %chatmessage% +``` + +## SSN Settings + +The setup page describes these required values in SSN: + +- Integration enabled. +- WebSocket URL, for example `ws://127.0.0.1:8080`. +- Password, only if Streamer.bot WebSocket auth is enabled. +- Action ID copied from Streamer.bot. + +If the password is blank in Streamer.bot, leave it blank in SSN. If auth is enabled in Streamer.bot, the SSN password must match exactly. + +## Payload Fields + +Common fields sent as Streamer.bot action arguments: + +| Field | Meaning | +| --- | --- | +| `chatmessage` | Message body. May include HTML when text-only mode is off. | +| `chatname` | Sender display name. | +| `userid` | Platform user ID when available. | +| `chatimg` | Sender avatar URL or data URL when available. | +| `bot` | Boolean bot marker when detected. | +| `mod` | Boolean moderator marker when detected. | +| `host` | Boolean broadcaster/host marker when detected. | +| `admin` | Boolean admin/channel-owner marker when detected. | +| `vip` | Boolean VIP marker when detected. | +| `originalPlatform` | Platform origin such as `youtube`, `twitch`, `kick`, etc. | +| `source` | Source label, often `SocialStream.Ninja`. | + +Additional fields may appear depending on platform and event type: + +| Field | Meaning | +| --- | --- | +| `contentimg` | Attached image/media URL or converted data URL. | +| `subtitle` | Extra platform status or metadata text. | +| `membership` | Membership/subscriber tier/status when available. | +| `hasDonation` | Donation/Super Chat/Rant amount label when available. | +| `type` | SSN source type. | +| `id` | Message ID when available. | +| `nameColor` | Sender name color when available. | +| `chatbadges` | Badge data or badge images when available. | +| `textonly` | Whether SSN stripped HTML from the message. | +| `tid` | Transaction/dedupe ID when available. | +| `meta` | Structured source-specific extra data when available. | + +## Optional C# Normalization + +The guide includes an optional C# sub-action that reads SSN arguments with `CPH.TryGetArg`, logs the message, and sets cleaner `ss_*` arguments such as: + +- `%ss_message%` +- `%ss_username%` +- `%ss_userId%` +- `%ss_avatar%` +- `%ss_platform%` +- `%ss_source%` +- `%ss_bot%` +- `%ss_mod%` +- `%ss_host%` +- `%ss_admin%` +- `%ss_vip%` + +Use C# when the user wants richer filtering, platform-specific handling, or consistent argument names. For basic echo/log/sound workflows, direct arguments are enough. + +## Common Recipes + +Filter out bots: + +- Add an If/Else sub-action early. +- Condition: argument `bot` equals `True`. +- Then branch: exit action or do nothing. + +Route by platform: + +- Condition on `originalPlatform`. +- Example: play one sound for `youtube`, another for `twitch`, and a fallback for everything else. + +Donation/Super Chat/Rant alert: + +- Check whether `hasDonation` is non-empty. +- Trigger a separate Streamer.bot alert action or OBS action. + +Update an OBS text source: + +- Use Streamer.bot's OBS sub-actions if available. +- Or write a text file from Streamer.bot and point an OBS text source at that file. + +## Troubleshooting + +Cannot connect: + +- Verify Streamer.bot WebSocket Server is enabled and running. +- Confirm the SSN URL matches the Streamer.bot port. +- Use `ws://127.0.0.1:8080` for same-machine setups. +- Check Windows firewall or security software if connecting across devices. +- Confirm the password matches only when Streamer.bot auth is enabled. + +Messages do not trigger the action: + +- Confirm the Action ID was copied from the target action, not the action name. +- Confirm the SSN Action ID field has the exact copied ID. +- Check Streamer.bot Action Queues/History to see whether the action is firing and failing. +- Add a simple Log Message sub-action first to prove the action is being invoked. +- Check SSN console logs for send/DoAction errors. + +C# compile errors: + +- Use `CPH.TryGetArg("key", out value)`. +- Do not assume old helper names exist in the user's Streamer.bot version. +- Check braces and argument names. +- Start with direct `%fieldname%` arguments if C# is not needed. + +Arguments are blank: + +- Confirm the sub-action supports argument substitution. +- Check exact casing of argument names. +- If using C# normalization, ensure the C# sub-action runs before sub-actions that use `%ss_*%`. +- Inspect a recent action run in Streamer.bot to see which arguments SSN sent. + +## Remaining Extraction Targets + +- Trace the exact background connection and DoAction request code in `background.js`. +- Cross-check current popup labels for the Streamer.bot settings fields. +- Verify current Streamer.bot v1.x UI paths against official Streamer.bot docs before publishing end-user step-by-step screenshots. diff --git a/docs/agents/09-api-and-integrations/tts.md b/docs/agents/09-api-and-integrations/tts.md index 21605217f..14f29fb76 100644 --- a/docs/agents/09-api-and-integrations/tts.md +++ b/docs/agents/09-api-and-integrations/tts.md @@ -1,32 +1,243 @@ # Text To Speech -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started from README, command docs, parameter docs, `tts.js`, and local TTS bridge docs. -## Purpose +## Source Anchors -Document SSN TTS features, providers, local/browser TTS, cloud TTS, routing, and troubleshooting. +- `README.md` +- `docs/commands.html` +- `docs/tts.html` +- `docs/local-tts.html` +- `parameters.md` +- `tts.html` +- `tts.js` +- `dock.html` +- `featured.html` +- `local-tts-bridge/README.md` +- `local-tts-bridge/server.cjs` -## Source Anchors +## What TTS Does + +SSN can read chat, featured messages, bot replies, and some events aloud. It can use browser/system voices, local/browser model providers, cloud providers, or OpenAI-compatible custom/local endpoints. + +The page that should produce audio must be open. For many workflows that means `dock.html`, `featured.html`, `bot.html`, `chatbot.html`, `cohost.html`, or another overlay/browser source. + +## Free vs Paid Boundaries + +| Provider/Mode | Cost Boundary | Notes | +| --- | --- | --- | +| System/Web Speech API | Free | Uses browser/OS voices; language/voice availability varies heavily. | +| Kokoro | Free/local in current docs | Runs in browser with WebGPU/CPU/WASM options; can require a powerful computer. | +| Kitten TTS | Free/local in current docs | Lightweight browser model download for local voice generation. | +| Local/custom OpenAI-compatible endpoint | Depends on self-hosted server | SSN can call local bridges/endpoints; user supplies compute/server. | +| Google Cloud TTS | Paid/Google account | Requires user's API key and provider billing/quotas. | +| ElevenLabs | Account/provider pricing | Free tier may exist for testing; account/API key required. | +| Speechify | Provider pricing | Account/API key/provider terms apply. | +| Gemini TTS | Provider/API pricing or preview terms | Requires key/model setup. | +| OpenAI TTS | Provider/API pricing | Requires API key unless using compatible local endpoint. | + +Do not promise that a third-party provider is free. Say SSN supports it, and the provider's own account/pricing applies. + +## Basic URL Parameters + +From `parameters.md`: + +| Parameter | Meaning | +| --- | --- | +| `speech` / `tts` | Enables TTS with language code such as `en-US`. | +| `volume` | TTS volume. | +| `rate` | Speaking rate. | +| `pitch` | Voice pitch. | +| `voice` | Partial voice-name match for system/browser voices. | +| `ttscommand` | Custom command to trigger TTS, defaulting to `!say` in docs. | +| `ttscommandmembersonly` | Restricts TTS command to members only. | +| `simpletts` | Simplified TTS output. | +| `readevents` | Enables TTS for stream events. | +| `readouturls` | Reads URLs instead of saying a generic link phrase. | + +Example: + +```text +featured.html?session=SESSION_ID&speech=en-US&volume=1&rate=1&pitch=1 +``` + +## Provider Parameters + +API key/provider parameters from `parameters.md`: + +- `ttskey` / `googlettskey` +- `elevenlabskey` +- `speechifykey` +- `geminikey` +- `openaikey` / `customttskey` / `localttskey` + +OpenAI-compatible/custom/local parameters: + +- `ttsprovider=openai` +- `ttsprovider=customtts` +- `ttsprovider=localtts` +- `openaiendpoint` / `customttsendpoint` / `localttsendpoint` +- `voiceopenai` / `customttsvoice` / `localttsvoice` +- `openaimodel` / `customttsmodel` / `localttsmodel` +- `openaispeed` / `customttsspeed` / `localttsspeed` +- `openaiformat` / `customttsformat` / `localttsformat` + +Provider-specific parameters also exist for Google, Gemini, ElevenLabs, and Speechify. Use `parameters.md` before answering exact parameter names. + +## System/Web Speech TTS + +System TTS is the simplest free path: + +```text +featured.html?session=SESSION_ID&speech=en-US +``` + +Important behavior from README: + +- Voice availability depends on OS and browser. +- Chrome/Edge can show local system voices and some cloud/browser voices. +- Firefox/Chromium variants may show only local voices or no useful voices. +- Standalone app may show a limited system voice list. +- Users can add OS language/voice packs, then restart browsers/apps. +- Some third-party SAPI/OS voices may not appear in Chromium browsers. + +Support test page: + +```text +https://socialstream.ninja/tts +``` + +## Kokoro And Browser Local TTS + +Current public docs describe Kokoro as a free browser-based TTS option that runs directly in the browser. Benefits: + +- Better OBS Browser Source capture than system TTS. +- No virtual audio cable when browser-source audio control works. +- Local/private generation. + +Limits: + +- It can be slow on weaker machines. +- WebGPU/CPU/WASM behavior depends on browser/platform. +- README mentions forcing WASM/q8 for browser overlays: + +```text +&kokorodevice=wasm&kokorodtype=q8 +``` + +Command docs also list Kitten TTS as a lightweight browser-based local model. Verify current model/download behavior before giving detailed support. + +## Cloud Provider TTS + +Provider setup pattern: + +1. Create provider account. +2. Generate API key. +3. Configure key and voice/provider settings in SSN page/menu/URL. +4. Open the TTS-producing page in OBS/browser. +5. Test with a short message before going live. + +Provider notes: + +- Google Cloud TTS requires a Google Cloud API key and enabled service. +- ElevenLabs requires account/API key; free tier may be available for testing. +- Speechify requires provider credentials. +- Gemini/OpenAI TTS require the relevant API/provider setup. + +## Local TTS Bridge + +`local-tts-bridge/README.md` documents a small Node server with no npm dependencies. It exposes: + +```text +http://127.0.0.1:8124/v1/audio/speech +``` + +SSN sends OpenAI-compatible JSON: + +```json +{ + "model": "tts-1", + "input": "Chat message text", + "voice": "nova", + "response_format": "wav", + "speed": 1 +} +``` + +Example SSN URL: + +```text +dock.html?session=SESSION_ID&speech=en-US&ttsprovider=customtts&openaiendpoint=http://127.0.0.1:8124/v1/audio/speech&voiceopenai=nova&openaiformat=wav +``` + +Bridge modes documented: + +- OpenAI-compatible servers, such as openedai-speech, Chatterbox, Kokoro-FastAPI, and similar `/v1/audio/speech` servers. +- GPT-SoVITS via bridge mode. +- F5-TTS wrappers via bridge mode. + +Desktop app note from the bridge README: standalone app windows may be less CORS constrained than Chrome, but the bridge remains the safest path for third-party local servers that do not allow browser requests or do not expose an OpenAI-compatible endpoint. + +## OBS Audio Capture + +README distinction: + +- System/Web Speech TTS often plays through the OS default output device, so OBS Browser Source audio control may not capture it. +- Provider/browser TTS options such as Kokoro, Google Cloud, ElevenLabs, and Speechify play through the browser page and are better suited to OBS Browser Source audio capture with "Control audio via OBS" enabled. + +System TTS capture options: + +- Route system audio through a virtual audio cable and capture that device. +- Use OBS Application Audio Capture on a process that carries system TTS where applicable. +- Use Desktop Audio capture, with the tradeoff that it captures other system sounds. + +Browser audio gate: + +- In normal browsers, users may need to click the page before audio playback is allowed. +- OBS Browser Sources and Electron Capture/app contexts can behave differently. + +## Dock/Featured Controls + +`dock.html` includes a TTS toggle. Disabling TTS stops playback and clears the queue. + +API actions: + +```json +{"action":"toggleTTS","value":"toggle"} +{"action":"tts","value":"on"} +``` + +HTTP/API example: + +```text +https://io.socialstream.ninja/SESSION_ID/toggleTTS/null/toggle +``` + +Verify current accepted HTTP path behavior against `api.md`/code before documenting a public user URL. + +## Common Failures -- `social_stream/tts.html` -- `social_stream/tts.js` -- `social_stream/docs/tts.html` -- `social_stream/docs/local-tts.html` -- `social_stream/local-tts-bridge/*` -- `ssapp/tts-worker.js` -- `ssapp/tests/electron/tts-diagnostics.js` -- `stevesbot/resources/instructions/social-stream-support.md` +| Symptom | Likely Cause | First Checks | +| --- | --- | --- | +| No voices listed | Browser/OS has no exposed voices | Test `https://socialstream.ninja/tts`; install OS language pack; restart browser/app. | +| TTS works in browser but not OBS | Wrong capture path | Check Browser Source audio control; system TTS may need virtual cable/desktop capture. | +| Cloud TTS fails | API key/model/provider issue | Verify key, billing/quota, selected voice/model, console errors. | +| Local TTS blocked by CORS | Local server not browser-safe | Use `local-tts-bridge` endpoint. | +| Audio starts only after click | Browser autoplay gate | Click page or use OBS Browser Source/app context. | +| Kokoro slow or broken | Device/runtime/model issue | Try WASM/q8 parameters or a lighter provider. | +| Firefox missing features | Firefox limitation | Test Chromium/app and check provider support. | +| TTS reads unsafe chat | User-generated content risk | Use filters, moderation, member-only command, or provider limits. | -## Starter Notes +## Safety Notes -Support guidance mentions system playback device behavior, OBS audio control, cloud API key restrictions, and provider-specific setup. +- Treat live chat TTS as user-generated audio. It can read offensive text, URLs, private information, or spam. +- Use moderation/filtering before enabling public TTS. +- Restrict `ttscommand` to members/moderators where needed. +- Avoid placing provider API keys in public screenshots or shared URLs. -## Planned Sections +## Follow-Up Extraction Needs -- Browser/system TTS -- Cloud providers -- Local TTS bridge -- App TTS worker -- URL parameters and settings -- OBS audio routing -- Common failures +- Line-level provider matrix from `tts.js`. +- Current exact popup setting names for every provider. +- App-specific TTS worker behavior from `ssapp`. +- E2E validation notes from `scripts/playwright-tts-provider-check.cjs`. diff --git a/docs/agents/09-api-and-integrations/websocket-http-api.md b/docs/agents/09-api-and-integrations/websocket-http-api.md index 3e528cd99..c4a651285 100644 --- a/docs/agents/09-api-and-integrations/websocket-http-api.md +++ b/docs/agents/09-api-and-integrations/websocket-http-api.md @@ -1,30 +1,363 @@ # WebSocket And HTTP API -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started from `api.md`, command docs, and public API examples. Verify command behavior against code before changing production automation. -## Purpose +## Source Anchors -Document SSN external control and message APIs. +- `api.md` +- `README.md` +- `docs/commands.html` +- `sampleapi.html` +- `sample_wss_source.html` +- `tests/sse.html` +- `background.js` +- `dock.html` +- `featured.html` -## Source Anchors +## What The API Does + +The SSN API lets external tools control the extension/app, dock, featured overlay, waitlist/polls/timer pages, and custom overlays. It also lets external apps receive chat messages when the user opts into relaying chat through the API server. + +Primary transports: + +- WebSocket: real-time bidirectional commands and chat listener workflows. +- HTTP GET: simple StreamDeck-style command buttons. +- HTTP POST/PUT: JSON command bodies. +- Server-Sent Events: simple one-way listener option. +- WebRTC SDK: alternate peer-to-peer option for developers who do not want to use the hosted relay. + +## Required Toggles + +The public API docs name these settings under Global settings > Mechanics: + +| Toggle | Required For | Notes | +| --- | --- | --- | +| Enable remote API control of extension | All API workflows | First setting to check when API commands do nothing. | +| Enable Dock to use and publish via API server | Commands directly to the dock | Needed for dock actions through the API server. | +| Send chat messages to API server | External chat listeners | Sends source chat to channel 4. | +| Dock sends its commands to Extension via server | Dock-to-extension via relay | Optional; used when direct P2P is not desired/working. | + +Support rule: if the user wants to receive chat in Python/Node, the third toggle is the one most often missed. + +## Session ID + +API endpoints use the same session ID as the dock/featured/app/extension. A wrong session ID looks like a dead API even when the endpoint format is correct. + +Do not publish real user session IDs in public logs. Session IDs can control overlays and, for webhook paths, can inject fake donation events. + +## WebSocket Connections + +Default remote-control connection: + +```javascript +const ws = new WebSocket("wss://io.socialstream.ninja/join/SESSION_ID"); + +ws.onopen = () => { + ws.send(JSON.stringify({ action: "clearOverlay" })); + ws.send(JSON.stringify({ action: "nextInQueue" })); + ws.send(JSON.stringify({ action: "sendChat", value: "Hello from API!" })); +}; +``` + +Explicit channel connection: + +```javascript +const ws = new WebSocket("wss://io.socialstream.ninja/join/SESSION_ID/IN_CHANNEL/OUT_CHANNEL"); +``` + +Connect then join: + +```javascript +const ws = new WebSocket("wss://io.socialstream.ninja"); + +ws.onopen = () => { + ws.send(JSON.stringify({ join: "SESSION_ID", in: 1, out: 2 })); +}; +``` + +## Receiving Chat + +Required toggles: + +- Enable remote API control of extension. +- Send chat messages to API server. + +External listeners should connect to channel 4: + +```javascript +const ws = new WebSocket("wss://io.socialstream.ninja/join/SESSION_ID/4"); + +ws.onmessage = (event) => { + const data = JSON.parse(event.data); + if (data.chatname) { + console.log(`[${data.type || "unknown"}] ${data.chatname}: ${data.chatmessage || ""}`); + } +}; +``` + +Minimal fields to expect: + +- `chatname`: display name. +- `chatmessage`: message body. +- `type`: source identifier such as `youtube`, `twitch`, `kick`, or `external`. + +Donation/event messages may include `hasDonation`, `membership`, `subtitle`, `event`, `contentimg`, `chatbadges`, and `meta`. + +## Channel Reference + +The public docs use channels for different components, but older docs sometimes describe channel 4 differently depending on page context. For external chat listeners, use `/4`. + +| Channel | Common External Meaning | Notes | +| --- | --- | --- | +| 1 | Main/default API command channel | Used by most remote-control examples. | +| 2 | Dock communication/output | Common when targeting dock workflows. | +| 3 | Extension communication | Used by extension/server routing internals. | +| 4 | Chat listener channel for external apps | Requires the "Send chat messages to API server" toggle. | +| 5 | Waitlist/giveaway workflows | Used by waitlist-related pages/actions. | +| 6-9 | Reserved/custom/future use | Verify before relying on one. | + +Channel-specific content actions: + +| Action | Output Channel | +| --- | --- | +| `content` | 1 | +| `content2` | 2 | +| `content3` | 3 | +| `content4` | 4 | +| `content5` | 5 | +| `content6` | 6 | +| `content7` | 7 | + +## HTTP API + +GET format: + +```text +https://io.socialstream.ninja/SESSION_ID/ACTION/TARGET/VALUE +``` + +If an action needs a value but no target, use `null`: + +```text +https://io.socialstream.ninja/SESSION_ID/sendEncodedChat/null/Hello%20World +https://io.socialstream.ninja/SESSION_ID/drawmode/null/toggle +``` + +POST/PUT formats: + +```text +https://io.socialstream.ninja/SESSION_ID +https://io.socialstream.ninja/SESSION_ID/ACTION +``` + +Example body: + +```json +{ + "action": "sendChat", + "value": "Hello from API!" +} +``` + +Channel override: + +```text +https://io.socialstream.ninja/SESSION_ID/sendChat/null/Hello?channel=2 +``` + +## Common Commands + +| Action | Purpose | Example Payload/URL | +| --- | --- | --- | +| `sendChat` | Send a chat response/message | `{"action":"sendChat","value":"Hello"}` | +| `sendEncodedChat` | Send URL-encoded chat text | `/SESSION/sendEncodedChat/null/Hello%20World` | +| `clearOverlay` | Clear featured overlay | `/SESSION/clearOverlay` | +| `clear` / `clearAll` | Clear dock messages, except pinned behavior may vary by page | `{"action":"clear"}` | +| `nextInQueue` | Feature the next queued message | `/SESSION/nextInQueue` | +| `getQueueSize` | Request queue size | `{"action":"getQueueSize","get":"queue-1"}` | +| `autoShow` | Toggle/set auto-show mode | `{"action":"autoShow","value":"toggle"}` | +| `feature` | Feature next unfeatured message | `{"action":"feature"}` | +| `blockUser` | Block a user by source/user | `{"action":"blockUser","value":{"chatname":"name","type":"twitch"}}` | +| `extContent` | Inject external content into processing | `{"action":"extContent","value":"{\"chatname\":\"User\",\"chatmessage\":\"Hello\"}"}` | +| `getChatSources` | Ask for active source list | `{"action":"getChatSources","get":"sources-1"}` | +| `toggleVIPUser` | Toggle VIP state for a user | `{"action":"toggleVIPUser","value":{"chatname":"name","type":"youtube"}}` | +| `getUserHistory` | Fetch user history where available | `{"action":"getUserHistory","value":{"chatname":"name","type":"kick"}}` | +| `drawmode` | Toggle/set draw mode | `{"action":"drawmode","value":"toggle"}` | +| `emoteonly` | Toggle/set global emote-only filtering | `{"action":"emoteonly","value":true}` | +| `toggleTTS` / `tts` | Toggle/set TTS state | `{"action":"toggleTTS","value":"toggle"}` | + +## Poll, Waitlist, And Timer Commands + +Poll controls documented in `api.md`: + +- `resetpoll` +- `closepoll` +- `loadpoll` +- `setpollsettings` +- `getpollpresets` +- `createpoll` + +Waitlist/giveaway controls: + +- `removefromwaitlist` +- `highlightwaitlist` +- `resetwaitlist` +- `downloadwaitlist` +- `selectwinner` +- `waitlistmessage` + +Timer controls: + +- `starttimer` +- `pausetimer` +- `toggletimer` +- `resettimer` +- `timeradd` +- `timersubtract` +- `settimer` +- `gettimerstate` + +Use `sampleapi.html` or code inspection before building workflows around less-common commands. + +## Message/Content Payload + +Minimum custom content: + +```json +{ + "chatname": "Username", + "chatmessage": "Message content", + "type": "external" +} +``` + +Common optional fields: + +| Field | Meaning | +| --- | --- | +| `chatimg` | Avatar URL or small data URI. | +| `contentimg` | Media attachment URL. | +| `hasDonation` | Display donation amount/unit. | +| `membership` | Member/subscription label. | +| `subtitle` | Secondary label, such as tenure or gifted-by detail. | +| `chatbadges` | Badge URLs or badge descriptors. | +| `textonly` | Whether `chatmessage` should be plain text. | +| `event` | Structured event name such as follow/raid/subscription. | +| `meta` | Extra structured details. | +| `id` | Unique message ID for ordering/dedup/routing. | + +`chatname`, `chatmessage`, and `type` are the safest baseline for integrations. + +## Targeting Specific Pages + +Add a label to the receiving page: + +```text +dock.html?session=SESSION_ID&label=control +featured.html?session=SESSION_ID&label=main +``` + +Then send a command with `target`: + +```json +{ + "action": "clearOverlay", + "target": "main" +} +``` + +For GET-style URLs, public docs also show target as the path segment: + +```text +https://io.socialstream.ninja/SESSION_ID/nextInQueue/control/null +``` + +Use labels when multiple docks/featured pages are open and commands must not hit every instance. + +## Server-Sent Events + +SSE endpoint: + +```javascript +const events = new EventSource("https://io.socialstream.ninja/sse/SESSION_ID"); +``` + +Demo page: + +```text +https://socialstream.ninja/tests/sse.html +``` + +Use SSE for simple receive-only browser integrations. Use WebSocket when commands and callbacks are needed. + +## Callbacks And Responses + +Some commands support a `get` field for responses: + +```json +{ + "action": "getQueueSize", + "get": "queue-size-1" +} +``` + +Expected callback shape: + +```json +{ + "callback": { + "get": "queue-size-1", + "result": true + } +} +``` + +Response states documented in `api.md` include success data, `failed`, `timeout`, and `special` for some non-default channel cases. + +## Inbound Donation Webhooks + +Supported webhook paths in `api.md`: + +| Service | URL Pattern | Notes | +| --- | --- | --- | +| Stripe | `https://io.socialstream.ninja/SESSION_ID/stripe` | Uses `checkout.session.completed`. | +| Ko-Fi | `https://io.socialstream.ninja/SESSION_ID/kofi` | Public donations only. | +| Buy Me A Coffee | `https://io.socialstream.ninja/SESSION_ID/bmac` | Supports donations and memberships. | +| Fourthwall | `https://io.socialstream.ninja/SESSION_ID/fourthwall` | Uses `ORDER_PLACED`. | + +Security rule: keep session IDs and webhook URLs private. The API docs say webhook URLs do not use signature verification. + +Duplication warning from `api.md`: do not enable both `&server` dock behavior and remote API control for webhook display unless the workflow intentionally handles duplicate donation alerts. + +## StreamDeck And Companion + +Simple StreamDeck path: + +```text +https://io.socialstream.ninja/SESSION_ID/sendEncodedChat/null/Hello%20Stream +``` -- `social_stream/api.md` -- `social_stream/background.js` -- `social_stream/dock.html` -- `social_stream/simple_api_client.html` -- `social_stream/sampleapi.html` -- `social_stream/tests/sse.html` +Bitfocus Companion has a Social Stream Ninja module. Public docs list common actions such as clear featured, clear all, next in queue, auto-show toggle, feature next, poll controls, waitlist controls, TTS controls, and send chat. Companion can expose variables such as queue size. -## Starter Notes +## Common Mistakes -Existing `api.md` covers WebSocket API, HTTP API, channels, responses, and special page controls. This page should turn that into agent-friendly, source-checked reference material. +- API toggle is off. +- Chat listener toggle is missing. +- Wrong session ID. +- User sends to channel 1 but listens on channel 4, or the reverse. +- User forgets URL encoding for GET `sendEncodedChat`. +- User targets a label that is not present on any dock/featured page. +- User expects a local custom file to run on a hosted page. +- User shares a webhook/session URL publicly. +- User uses old docs for channel meanings without checking the current `api.md`. -## Planned Sections +## Verification Checklist For Agents -- API server setup -- WebSocket channels -- HTTP endpoints -- SSE -- Sending commands -- Receiving chat -- Common mistakes +- Confirm exact endpoint and session format. +- Confirm required toggle(s). +- Confirm whether the target is extension, dock, featured, waitlist, poll, timer, or custom page. +- Confirm channel number. +- Test with `clearOverlay` or `nextInQueue` before debugging complex payloads. +- Use `sampleapi.html` to reproduce a user command. +- For chat listeners, verify channel 4 with a minimal WebSocket client. +- For webhook issues, verify duplicate settings and secret/session exposure risk. diff --git a/docs/agents/10-troubleshooting/auth-and-sign-in.md b/docs/agents/10-troubleshooting/auth-and-sign-in.md index f5d0c8805..8c5627275 100644 --- a/docs/agents/10-troubleshooting/auth-and-sign-in.md +++ b/docs/agents/10-troubleshooting/auth-and-sign-in.md @@ -1,27 +1,220 @@ # Auth And Sign-In -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started. ## Purpose -Document platform sign-in, OAuth, cookie/session, and embedded-browser restrictions. +Document platform sign-in, OAuth, cookie/session, callback ports, and embedded-browser restrictions for SSN. + +This page is source-backed for desktop app OAuth helper structure and support-derived for general platform blocking behavior. Platform-specific source pages still need intense passes for exact scopes and event availability. ## Source Anchors -- `ssapp/resources/electron-*-handler.js` +- `ssapp/resources/electron-youtube-handler.js` +- `ssapp/resources/electron-twitch-handler.js` +- `ssapp/resources/electron-kick-handler.js` +- `ssapp/resources/electron-facebook-handler.js` +- `ssapp/resources/electron-spotify-handler.js` +- `ssapp/resources/electron-velora-handler.js` +- `ssapp/resources/electron-vpzone-handler.js` +- `ssapp/preload.js` +- `ssapp/main.js` - `social_stream/sources/websocket/*.html` - `social_stream/sources/websocket/*.js` - `stevesbot/resources/instructions/social-stream-support.md` -## Starter Notes +## Core Rule + +Always identify the auth surface before troubleshooting: + +- Chrome extension using the user's existing browser login. +- Desktop app embedded/source window using an Electron session. +- Desktop app OAuth helper opening the system browser and listening on a local callback port. +- Desktop app local OAuth window, where supported by a handler. +- Platform API/WebSocket mode that requires scopes/tokens. + +The same platform can behave differently across those surfaces. + +## Desktop OAuth Helper Matrix + +Source-checked handlers: + +| Platform/helper | Callback ports | Callback path | Browser/window behavior | Notes | +| --- | --- | --- | --- | --- | +| YouTube | `8181`, then `8080` | `/sources/websocket/youtube.html` | Opens default browser with `shell.openExternal`. | Supports hosted auth URL or custom Google mode; exchanges/refreshes tokens through handler functions. | +| Twitch | `8181`, then `8080` | `/sources/websocket/twitch.html` | Opens default browser with `shell.openExternal`. | Uses implicit token flow; callback page posts hash token to local `/token`. | +| Kick | `8181`, then `8080` | `/sources/websocket/kick.html` | Can use external browser or a local OAuth window depending on payload. | Uses PKCE. Local window can reuse parent webContents session and optional preload/user-agent settings. | +| Facebook | `8181`, then `8080` | `/sources/websocket/facebook.html` | Opens external hosted auth flow and local loopback receives result. | Uses `auth.socialstream.ninja` by default. | +| Velora | `8181`, then `8080` | `/sources/websocket/velora.html` | Opens external hosted auth flow and local loopback receives result. | Uses `sso.socialstream.ninja` by default. | +| VPZone | `8181`, then `8080` | `/sources/websocket/vpzone.html` | Opens default browser with `shell.openExternal`. | Uses PKCE and exchanges the authorization code at `vpzone.tv`. | +| Spotify | `8888`, then `8080`, then `8181` | `/callback` or requested callback path | Default mode uses loopback and default browser; can fall back to intercept mode. | Spotify app redirect URIs should include the loopback URLs for the configured ports. | + +Port conflict guidance: + +- If the app shows a port conflict for YouTube/Twitch/Kick/Facebook/Velora/VPZone, check ports `8181` and `8080`. +- If Spotify auth fails, also check `8888`. +- Streamer.bot commonly uses `8080`, so it can block fallback auth. +- Do not claim there is a UI setting to change these ports unless source confirms it for that handler. + +## What The Port Flow Does + +For loopback OAuth handlers: + +1. The app starts a temporary HTTP server on `127.0.0.1`. +2. It tries the configured ports in order. +3. It builds a redirect URI using the successful port. +4. It opens the auth URL in the default browser or local auth window. +5. The platform redirects back to the local callback URL. +6. The app verifies state/code/token payload and closes/cleans up the temporary server. +7. A 5-minute timeout is common across these handlers. + +Failure points: + +- Both callback ports are occupied. +- The default browser profile is not the logged-in profile. +- The platform rejects the redirect URI. +- State mismatch. +- User closes auth window. +- Platform returns an OAuth error. +- Firewall/security software blocks loopback. + +## Extension Auth + +The extension usually relies on the browser's current session and cookies. That makes it the safer recommendation when: + +- The user can sign into the platform in Chrome but the app cannot. +- The platform has CAPTCHA or anti-bot checks in embedded browsers. +- The platform blocks "browser not supported" app contexts. +- The source is page/DOM based rather than API-token based. + +Do not tell users to uninstall the extension to fix auth. Uninstalling can remove extension storage. Reload/update the extension instead. + +## Desktop Embedded Auth + +The app has mitigations for some embedded-browser issues: + +- Header overrides and Electron header stripping hooks exist for activated windows. +- LinkedIn passkey initiation can be blocked for specific activated windows. +- Kick can choose a local OAuth window and optionally use preload/user-agent behavior. +- Startup flags can influence locale, local assets, TikTok classic mode, and multiple instances. + +These mitigations do not guarantee platform login success. If the site is actively blocking embedded browsers, switch to extension or external-browser/WebSocket flow when available. + +## Platform Notes + +### YouTube / Google + +Source-backed: + +- Desktop helper uses loopback ports `8181` and `8080`. +- It can open a hosted Social Stream auth flow or custom Google auth mode. +- It has exchange and refresh handlers for OAuth tokens. + +Support-derived: + +- Google may reject embedded browser sign-in. +- Users may need the normal browser, extension, or WebSocket/API flow. + +Need verification: + +- Exact current YouTube source modes, gift/membership scopes, moderation behavior, and UI labels. + +### Twitch + +Source-backed: + +- Desktop helper uses loopback ports `8181` and `8080`. +- Twitch token is returned in URL hash and posted to the local `/token` endpoint. + +Support-derived: + +- Users often need to press `Activate` after adding/signing in. +- Channel points/subscriptions/bans may require EventSub/WebSocket scopes rather than basic chat/IRC. + +Need verification: + +- Current EventSub scope matrix and event payloads. + +### Kick + +Source-backed: + +- Desktop helper uses loopback ports `8181` and `8080`. +- Uses PKCE. +- Supports external and local auth-window modes. +- Local window can reuse the parent session and apply selected preload/user-agent settings. + +Support-derived: + +- CAPTCHA or human verification can block embedded login. +- Copying an external-browser auth URL into the correct browser profile may help when the default browser is wrong. + +Need verification: + +- Current Kick connection-mode UI and WebSocket source behavior. + +### Facebook / Velora + +Source-backed: + +- Both use loopback ports `8181` and `8080`. +- Both rely on hosted Social Stream auth starts by default and return encoded result/error payloads to the local callback. + +Need verification: + +- Current source setup UI, required account/page permissions, and token persistence. + +### Spotify + +Source-backed: + +- Spotify uses `8888`, `8080`, then `8181`. +- Loopback mode opens the default browser. +- If loopback ports are unavailable and fallback is enabled, it can use intercept mode. +- The handler expects Spotify app redirect URIs for the loopback callback URLs. + +Support note: + +- If Spotify auth fails, collect the attempted redirect URI and whether the user's Spotify app includes that redirect URL. + +### VPZone + +Source-backed: + +- VPZone uses loopback ports `8181` and `8080`. +- It uses PKCE and exchanges code at `https://vpzone.tv/api/oauth/token`. +- Default scopes include profile, channel, and chat read. + +Support-derived: + +- Recent support records mention username casing/source-button issues; verify in source before publishing as final advice. + +## Common User-Facing Troubleshooting Flow + +1. Ask which surface is being used: extension or app. +2. Ask which platform and mode: Standard, WebSocket, EventSub/API, external browser, or local auth window. +3. Ask whether auth opens in the default browser or an app window. +4. If there is a port error, check the platform helper's ports. +5. If no port error appears, check whether the browser profile that opened is logged into the right account. +6. If embedded login is blocked, try the extension or external-browser flow. +7. After successful auth, stop and re-activate the source. +8. If the platform can send messages, test manual send in the platform before debugging SSN automation. + +## Evidence To Collect -Support history mentions Google, Twitch, Kick, LinkedIn, TikTok, and app embedded-browser sign-in blocks. Exact advice should be platform-specific and source-checked. +- Exact platform and source mode. +- Screenshot/error text. +- Whether the auth page opens in browser or app. +- Which port conflict message appears, if any. +- Whether Streamer.bot, another local server, Docker, or streaming tool is using `8080`, `8181`, or `8888`. +- Whether the user has multiple browser profiles. +- Whether extension capture works in Chrome. +- Whether clearing browser data or source reactivation changes behavior. -## Planned Sections +## Open Verification Tasks -- Browser extension auth -- Standalone app auth -- OAuth helpers -- Cookie/session persistence -- Platform-specific auth notes -- Common loops and blocks +- Check current UI labels for each auth mode. +- Build exact port-conflict user flow for each platform. +- Source-check token storage and refresh behavior per platform. +- Source-check which platforms require reactivation after auth. +- Add per-platform scope/event availability matrices. diff --git a/docs/agents/10-troubleshooting/desktop-app-issues.md b/docs/agents/10-troubleshooting/desktop-app-issues.md index 54fdc43d2..131667dfe 100644 --- a/docs/agents/10-troubleshooting/desktop-app-issues.md +++ b/docs/agents/10-troubleshooting/desktop-app-issues.md @@ -1,29 +1,163 @@ # Desktop App Issues -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started. ## Purpose -Document common standalone app issues and differences from the Chrome extension. +Document common standalone app support issues and the operational differences between the SSN desktop app and the Chrome extension. + +The app is a host for Social Stream source files. For Social Stream feature behavior, use `C:\Users\steve\Code\social_stream` as the source of truth. For desktop shell behavior, use `C:\Users\steve\Code\ssapp`. ## Source Anchors - `ssapp/main.js` - `ssapp/preload.js` - `ssapp/state.js` -- `ssapp/README.md` -- `ssapp/tests/electron/*` +- `ssapp/settings-backup.js` +- `ssapp/transfer-backup.js` +- `ssapp/transfer-restore-runner.js` +- `ssapp/tests/electron/settings-transfer-e2e.js` +- `ssapp/tests/electron/settings-loss-diagnostics.js` +- `ssapp/tests/electron/settings-rootcause-diagnostics.js` - `stevesbot/resources/instructions/social-stream-support.md` +- `stevesbot/resources/learnings/social-stream-ninja-top-issues.md` + +## App vs Extension Boundary + +Use the desktop app when the user needs app-managed source windows, standalone packaging, local server controls, full-session backup/restore, app-side OAuth helpers, or app-specific TikTok connection handling. + +Use the Chrome extension when the platform blocks embedded browser sessions, depends on an existing logged-in browser profile, or is easier to capture from a normal visible browser tab. + +Support history repeatedly shows that Google, Kick, Rumble, and other protected sites may reject embedded or app-created browser contexts. Do not present the desktop app as universally easier than the extension. + +## Source Loading And Local Files + +Confirmed from `ssapp/main.js`: + +- The app can run from source with `--running-from-source`. +- `package.json` includes commands such as `npm run start2` and `npm run start3` that pass source-mode flags. +- A `--filesource` value can point the app at a local Social Stream source folder. +- Saved local source roots are validated before reuse. +- A valid local Social Stream source folder must include `manifest.json`, `background.html`, `popup.html`, and `sources/twitch.js`. +- Local source can be loaded from a folder or from a ZIP; ZIP extraction happens under the app user-data folder before validation. +- Startup Preferences can persist `preferLocalAssets`, `forceTikTokClassic`, and `allowMultipleInstances`. + +Important support rule: + +- Do not tell users to edit the packaged fallback mirror for normal work. +- For source edits, use `C:\Users\steve\Code\social_stream`. +- If the app is pointed at the wrong local folder, clear the saved local source or reload with a validated Social Stream source folder. + +## Window And Tray Behavior + +Confirmed from `ssapp/main.js`: + +- The Window menu has `Minimize to Tray`. +- The Window menu has a `Close to Tray` checkbox persisted in `startupFlags.closeToTray`. +- Startup Preferences includes startup flags and requires restart after save/reset. +- The app has a right-click menu item to make windows unclickable until focus shortcut handling. +- Window state restore has diagnostic support under `ssapp/tests/electron/window-state-diagnostics.js`. + +Support handling: + +- If the app appears closed but still running, check the tray first. +- If a window is unclickable, use the app/window controls or restart the app if the shortcut is not known. +- If a window opens off-screen or wrong-sized, use window-state diagnostics or reset relevant app state rather than reinstalling blindly. + +## Reset Options + +The app has different reset levels: + +| Action | Source-backed behavior | When to use | +| --- | --- | --- | +| Clear All Sources | Sends `app:clear-all-sources`; keeps app sessions, cookies, and other settings intact. | Bad source list, duplicate/stale sources, source setup confusion. | +| Reset Everything / Full Reset | Clears store data, localStorage keys, cookies/cache/storage for sessions and partitions, and reloads the main window. It preserves stream ID/password when possible. | Corrupt app state, bad cached sessions, stuck embedded browser data. | +| Settings Backup export/import | Saves and restores recognized Social Stream settings plus selected app localStorage keys. | Normal settings migration or before risky changes. | +| Advanced Full Session Transfer | Encrypted `.ssappbk` backup/restore of the Electron user-data folder. Restore replaces local session data and keeps a pre-restore copy. | Whole-profile migration, not routine settings moves. | + +Do not advise Full Session Transfer for a simple overlay/session settings export unless the user needs a whole app profile move. + +## Local Server + +The File menu includes `Enable Local Server` / `Stop Local Server`. The local server is app-side infrastructure, not a replacement for hosted overlay URLs in OBS. + +Support guidance: + +- If a user asks for OBS overlay URLs, use hosted `socialstream.ninja` overlay/dock URLs unless they are explicitly developing local files. +- If a local server feature fails, collect port, firewall, and exact URL/action details. + +## Common Desktop-App Symptoms + +### App Sign-In Fails + +Likely causes: + +- Protected site rejects embedded/app browser. +- OAuth callback port is occupied. +- Default browser/profile is not the one where the user is signed in. +- Platform auth changed. + +First checks: + +- Which platform and which connection mode? +- Does the Chrome extension work in a normal browser profile? +- Does the app show a port conflict? +- Did the auth page open in a separate browser window? +- Is another app using ports listed in `auth-and-sign-in.md`? + +### Settings Look Wiped + +Likely causes: + +- Real disk/user-data loss. +- LocalStorage or cached-state hydration race. +- Cleanup tool/security software removed app data. +- User performed a full reset. +- User is running a different app profile/user-data path. + +Use `settings-loss-and-backups.md` for detailed handling. + +### Source Windows Reopen Or Do Not Stay Hidden + +Support history mentions hidden capture pages reopening with auto-activate in older builds. Current source has source persistence, auto-activate flags, and tests/diagnostics around settings loss, but this specific issue needs a current source pass before being documented as current behavior. + +Collect: + +- App version. +- Source target. +- Whether auto-activate is enabled. +- Whether the source is Standard/page mode or WebSocket/API mode. +- Whether the issue survives after clearing sources. + +### App Uses Wrong Social Stream Source + +Check: + +- `--filesource` command-line argument. +- Saved `localSourcePath`. +- Startup Preference: Prefer bundled/local assets. +- Whether the selected folder passes validation. +- Whether the app is on `beta` or `main` Social Stream branch. + +If local source is invalid, the app clears/ignores the saved path and falls back to online/packaged assets. + +## Reporting Checklist -## Starter Notes +Ask for: -The app can hit embedded browser login restrictions, settings/persistence issues, source loading issues, and platform-specific differences. It uses the `social_stream` repo as source of truth for loaded Social Stream files. +- App version and OS. +- Exact platform source and connection mode. +- Whether it is desktop app or Chrome extension. +- Whether local source / ZIP / `--filesource` is being used. +- Whether Startup Preferences are changed. +- Session ID mismatch symptoms, without asking user to post private session IDs publicly. +- Screenshot of any app error dialog. +- For auth: exact port conflict or OAuth error text. +- For settings loss: whether `File -> Settings Backup` exists, and whether `savedSync.json` appears in the app user-data folder. -## Planned Sections +## Open Verification Tasks -- Source window issues -- Embedded auth blocks -- App state/persistence -- Source file resolution -- App update/build confusion -- When to recommend Chrome extension instead +- Source-check every startup flag and document its CLI/env/store equivalent. +- Source-check app source-window lifecycle, hidden/visible state, auto-activate, and reconnect behavior. +- Source-check platform-specific source windows with current source files. +- Convert settings-loss diagnostics into a user-safe troubleshooting flow after current in-app verification. diff --git a/docs/agents/10-troubleshooting/extension-not-capturing.md b/docs/agents/10-troubleshooting/extension-not-capturing.md index 892653a3f..6063de4ec 100644 --- a/docs/agents/10-troubleshooting/extension-not-capturing.md +++ b/docs/agents/10-troubleshooting/extension-not-capturing.md @@ -1,29 +1,155 @@ # Extension Not Capturing -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started from README, manifest/source patterns, platform docs, and existing triage notes. -## Purpose +## Source Anchors -Document what to check when the Chrome extension is installed but messages do not appear. +- `README.md` +- `manifest.json` +- `service_worker.js` +- `background.js` +- `popup.html` +- `sources/*.js` +- `sources/websocket/*` +- `docs/agents/10-troubleshooting/quick-triage.md` +- `docs/agents/08-platform-sources/*.md` -## Source Anchors +## Fast Triage + +Ask these first: + +1. Is the extension icon green/enabled? +2. Was the chat page opened/reloaded after the extension was installed or reloaded? +3. Is the user on the correct source mode: popout chat, normal page, toggle-required page, manual picker, or WebSocket source page? +4. Is the chat page visible and not minimized? +5. Does `dock.html` use the same session ID as the extension? +6. Does VDO.Ninja/WebRTC work in the same browser/network? +7. Are other extensions, privacy tools, or browser profiles interfering? +8. Is the platform currently supported by a source file and manifest match? + +## Enabled State + +README guidance: + +- Red extension icon means disabled/off. +- Green extension icon means enabled. +- If the extension is enabled after a chat page already loaded, reload the chat page. + +If the user only loaded `dock.html`/`featured.html` but never opened a supported chat/source page, there is nothing to capture. + +## Source Mode + +Common setup types: + +| Mode | Example | Support Check | +| --- | --- | --- | +| Popout chat | Twitch, YouTube live, Kick, Rumble variants | User opened exact popout/chat URL. | +| Standard page | Facebook Live, TikTok live, some meeting/chat sites | Chat panel is visible on the page. | +| Toggle-required | Discord, Slack, Telegram, WhatsApp, Google Meet, ChatGPT/static comments | Relevant extension setting is enabled, then page reloaded. | +| Manual picker | YouTube comments, X posts, Threads | User clicks SS/manual selection control. | +| WebSocket source | YouTube/Twitch/Kick/API/IRC style source pages | Source page is configured and connected. | +| App source | Standalone app managed source | Check app-specific source window and auth. | + +Use `docs/js/sites.js`, README, manifest entries, and platform agent docs to identify the correct mode. + +## Visibility And Browser Throttling + +README notes browser pages can pause or throttle hidden/minimized chat windows. + +Support steps: + +- Do not minimize source chat windows. +- Keep the chat visible, even if only a small part is visible. +- Keep the chat scrolled to newest messages. +- Disable browser performance/background tab throttling if needed. +- Check `chrome://discards/` and disable auto-discard for source pages. +- Consider the standalone app when browser throttling keeps breaking capture. + +## Session Mismatch + +If the dock/overlay shows nothing, verify: + +- Extension/app session ID. +- `dock.html?session=...` +- `featured.html?session=...` +- Any API/session field in source pages. + +If the user opened a new dock/overlay link from the popup, the session may have changed from the old saved URL. + +## Platform-Specific First Checks + +| Platform | First Check | +| --- | --- | +| YouTube Live | Use popout/studio/guest live chat or supported watch URL; reload after extension changes. | +| YouTube Static Comments | Use SS manual comment selection control. | +| Twitch | Use Twitch popout chat for extension capture. | +| TikTok | Keep live chat open/visible when using extension capture. | +| Kick | Confirm chatroom/popout/source mode and current Kick source doc. | +| Facebook Live | Check viewer/publisher/producer chat mode and network/auth. | +| Discord/Slack/Telegram/WhatsApp/Meet | Enable required capture toggle and reload page. | +| ChatGPT/OpenAI page | Requires opt-in toggle. | + +## Conflicts And Browser State + +Try: + +- Incognito/private window with only SSN enabled. +- Disable other extensions temporarily. +- New Chrome/Edge profile. +- Clear only the affected site/session if login/cookie state looks broken. +- Test on Chromium if Firefox is missing required feature support. + +Do not immediately blame SSN source code until a clean profile is tested for extension conflict issues. + +## Auto-Responder Is Not Capture + +Capture can work while auto-responder/send-chat fails. + +Auto-response requires: + +- Source page can send chat manually. +- User is signed in and has permission to chat. +- Relevant command toggle is enabled. +- Chromium/debugger API behavior is available for that source/mode. + +If the user sees a blue debugger bar, README says Chrome can be started with `--silent-debugger-extension-api` to hide that warning. + +## Manifest/Source Verification For Agents + +When a source is suspected broken: + +1. Check `manifest.json` for URL match pattern. +2. Check the relevant `sources/*.js` or `sources/websocket/*.js`. +3. Confirm the source type used in payload (`data.type`). +4. Check whether a toggle gates that source. +5. Check recent platform agent doc notes. +6. If app-specific, check `ssapp` source loading/auth handling, not the fallback bundle. + +## Common Resolutions -- `social_stream/manifest.json` -- `social_stream/service_worker.js` -- `social_stream/background.js` -- `social_stream/popup.html` -- `social_stream/sources/*.js` -- `stevesbot/resources/instructions/social-stream-support.md` +- Turn the extension on. +- Reload the source chat page. +- Use the correct popout/chat URL. +- Keep the chat visible/not minimized. +- Match the session ID. +- Enable the toggle-required source. +- Disable conflicting extensions. +- Use manual GitHub build if the store build is behind a recent fix. +- Use the standalone app if Chrome throttling is the main issue. -## Starter Notes +## Escalation Data To Collect -Support guidance says to check whether the extension icon is enabled, whether chat is popped out, whether the session ID matches, and whether other extensions or browser state are interfering. +- Browser and extension install path/store/manual branch. +- Source platform and exact URL pattern, redacted if private. +- Screenshot of extension popup/source toggle state. +- Screenshot of dock URL, with session ID redacted. +- Console errors from the source page and dock. +- Whether it reproduces in a clean browser profile. +- Whether standalone app works for the same source. -## Planned Sections +## Follow-Up Extraction Needs -- Enabled/disabled extension state -- Source page loaded -- Pop-out chat requirements -- Session mismatch -- Browser restrictions -- Platform-specific capture problems +- Mine support DBs for high-frequency capture symptoms. +- Build a per-platform capture-mode table from manifest and site metadata. +- Add exact Firefox/MV3 limitation matrix. +- Add console-error examples for common source failures. diff --git a/docs/agents/10-troubleshooting/index.md b/docs/agents/10-troubleshooting/index.md index 21376d5e6..96b58176d 100644 --- a/docs/agents/10-troubleshooting/index.md +++ b/docs/agents/10-troubleshooting/index.md @@ -1,6 +1,6 @@ # Troubleshooting Index -Status: framework only. Detailed extraction not started. +Status: framework plus quick triage, extension capture, OBS overlay, desktop app, auth, settings/backup, and support-mined platform known-issue passes. ## Purpose @@ -8,10 +8,18 @@ This section converts code, docs, tests, and support history into practical trou ## Pages -- `quick-triage.md` -- `extension-not-capturing.md` -- `desktop-app-issues.md` -- `auth-and-sign-in.md` -- `obs-overlay-display.md` -- `settings-loss-and-backups.md` -- `platform-known-issues.md` +- `quick-triage.md`: backbone extraction pass complete. +- `extension-not-capturing.md`: heavy extraction pass started. +- `desktop-app-issues.md`: heavy extraction pass started. +- `auth-and-sign-in.md`: heavy extraction pass started. +- `obs-overlay-display.md`: heavy extraction pass started. +- `settings-loss-and-backups.md`: heavy extraction pass started. +- `platform-known-issues.md`: heavy support extraction pass started. + +## Suggested Next Pass + +- Source-check desktop source-window lifecycle, hidden/visible behavior, and auto-activate reconnect logic. +- Intense extraction for extension export/import behavior and Event Flow storage. +- Intense extraction for OAuth scopes and event availability per platform. +- Source-check `platform-known-issues.md` against current platform files and app handlers. +- Intense support-history pass against `stevesbot` SQLite files. diff --git a/docs/agents/10-troubleshooting/obs-overlay-display.md b/docs/agents/10-troubleshooting/obs-overlay-display.md index 21228dcd8..62d7b317b 100644 --- a/docs/agents/10-troubleshooting/obs-overlay-display.md +++ b/docs/agents/10-troubleshooting/obs-overlay-display.md @@ -1,28 +1,179 @@ # OBS Overlay Display Issues -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started from README, `dock.html`, `featured.html`, `parameters.md`, Event Flow docs, and OBS integration notes. -## Purpose +## Source Anchors -Document blank, white, transparent, stale, hidden, incorrectly styled, or non-updating overlays in OBS/browser. +- `README.md` +- `dock.html` +- `featured.html` +- `parameters.md` +- `docs/customoverlays.md` +- `themes/featured-styles/README.md` +- `actions/event-flow-guide.html` +- `obs-websocket-test.html` +- `docs/agents/09-api-and-integrations/obs.md` -## Source Anchors +## First Distinction + +Determine which page the user loaded: + +| Page | Expected Role | +| --- | --- | +| `dock.html` | Operator dashboard/control page. May look like a chat dashboard, not a clean overlay. | +| `featured.html` | Selected-message overlay. Can be blank/transparent until a message is featured. | +| `actions.html` | Event Flow output/actions overlay. Must stay open for media/audio/OBS actions. | +| `sampleoverlay` / custom overlay | Minimal/custom renderer; may not support all dock/featured parameters. | +| `themes/featured-styles/*` | Styled featured-message overlay variants. | + +Many "blank overlay" reports are actually correct empty/transparent featured overlays with no selected message yet. + +## Quick Checks + +1. Does the Browser Source URL include `session=SESSION_ID`? +2. Does that session match the extension/app/dock? +3. Is there an active source sending messages? +4. Can the dock see messages? +5. If using featured overlay, did the user click a dock message or send API `content`? +6. Is the OBS Browser Source visible on the active scene? +7. Has the source been refreshed after URL/CSS/settings changes? +8. Is custom CSS hiding text or making text/background the same color? + +## Blank Or Transparent Featured Overlay + +Normal cases: + +- No message is currently featured. +- `showtime` expired and cleared the message. +- The overlay is transparent for OBS compositing. + +Test: + +```text +https://socialstream.ninja/featured.html?session=SESSION_ID +``` + +Then click a message in: + +```text +https://socialstream.ninja/dock.html?session=SESSION_ID +``` + +If the browser appears white before a message is featured, do not treat that alone as failure. + +## Wrong Page Or Wrong Session + +Symptoms: + +- Dock shows messages but overlay does not. +- User has multiple old URLs. +- Store/manual/app session changed. +- API commands affect a different page. + +Fix: + +- Copy a fresh dock/featured link from the extension/app. +- Compare session IDs exactly. +- Use labels for multiple pages: + +```text +featured.html?session=SESSION_ID&label=main +dock.html?session=SESSION_ID&label=control +``` + +## OBS Browser Source Size + +README recommends `1280x600` or `1920x600` for many overlay layouts. Featured-style full-canvas themes and `actions.html` often fit `1920x1080`. + +If text is cropped: + +- Increase Browser Source height. +- Reduce `scale`. +- Check CSS font sizes. +- Crop intentionally in OBS only after the overlay has enough room. + +README also notes holding ALT in OBS can resize/crop elements. + +## CSS Problems + +Common CSS issues: + +- Text color equals background color. +- CSS copied into wrong OBS source. +- Missing `!important` where SSN page styles override custom CSS. +- Local CSS file path blocked or unavailable. +- URL-encoded/base64 CSS malformed. +- `transparent` or `chroma` makes the page look empty in a normal browser. + +Safer paths: + +- Use OBS Browser Source custom CSS field. +- Use hosted `socialstream.ninja` page. +- Use `css`/`cssb64` parameters only after testing the generated URL. + +README warns that local self-hosted featured/dock files can be problematic in OBS on macOS/Linux; hosted pages or OBS CSS are safer. + +## Stale Browser Source + +If the overlay used to work: + +- Refresh the Browser Source. +- Toggle source visibility. +- Clear OBS browser cache if needed. +- Recreate the Browser Source when cached state is clearly stale. +- Ensure "Shutdown source when not visible" is not stopping pages that must remain connected. +- For Event Flow, keep `actions.html` open/running. + +## TTS Audio In OBS + +If visual overlay works but TTS is silent: + +- Identify provider/mode. +- System/Web Speech TTS may require virtual cable, desktop audio, or app audio capture. +- Browser/provider TTS works better with Browser Source audio control. +- Normal browser pages may need a click before audio starts. +- OBS Browser Sources can avoid some browser autoplay prompts. + +See `../09-api-and-integrations/tts.md`. + +## OBS Remote Control Issues + +Scene/source/filter controls need one of: + +- Browser Source API: SSN page running inside OBS Browser Source with Advanced Access Level. +- OBS WebSocket v5: OBS 28+ server, usually `ws://127.0.0.1:4455`. + +`obs-websocket-test.html` is the diagnostic path for WebSocket requests. Old obs-websocket 4.x / port `4444` setups are not compatible with current Flow Actions request behavior. + +## Common Fix Matrix -- `social_stream/dock.html` -- `social_stream/featured.html` -- `social_stream/docs/customoverlays.md` -- `social_stream/parameters.md` -- `stevesbot/resources/learnings/playbooks/playbook-obs-overlay-issues.md` +| Symptom | Likely Fix | +| --- | --- | +| Blank featured page | Feature a message; check `showtime`; verify session. | +| White page in browser | Test in OBS or add temporary background; this can be transparent empty state. | +| Dock works, OBS does not | Refresh/recreate OBS Browser Source; check active scene/source visibility. | +| Overlay text cropped | Increase Browser Source height or reduce scale/CSS font size. | +| Styling ignored | Use OBS CSS field and `!important`; verify CSS target selectors. | +| Local file works in browser but not OBS | Use hosted page or OBS CSS, especially macOS/Linux. | +| Audio missing | Use provider/browser TTS or route system TTS audio. | +| Event Flow media missing | Open `actions.html?session=...` and keep it running. | +| OBS scene control missing | Use Advanced Access Browser Source or OBS WebSocket v5. | -## Starter Notes +## Escalation Data To Collect -Common causes include missing session ID, using the wrong page, transparent backgrounds, stale OBS browser source cache, CSS hiding text, and unmatched dock/overlay sessions. +- OBS version. +- Browser Source URL with session/key values redacted. +- Which page is loaded: dock, featured, actions, custom, theme. +- Browser Source dimensions. +- Custom CSS used. +- Screenshot of dock and OBS output. +- Whether dock sees messages. +- Whether a simple `clearOverlay` or `content` API command works. +- OBS WebSocket URL/version/password-required status for control issues. -## Planned Sections +## Follow-Up Extraction Needs -- Dock vs featured confusion -- Missing or wrong session -- Transparent output -- White text/background styling -- Refresh/cache issues -- Browser source permissions +- Add screenshot examples for empty featured overlay vs broken overlay. +- Extract common CSS selectors for dock/featured styling. +- Mine OBS-specific support history from `stevesbot`. +- Document OBS Browser Source permission UI by OBS version. diff --git a/docs/agents/10-troubleshooting/platform-known-issues.md b/docs/agents/10-troubleshooting/platform-known-issues.md index b1b8307ec..08e2c0972 100644 --- a/docs/agents/10-troubleshooting/platform-known-issues.md +++ b/docs/agents/10-troubleshooting/platform-known-issues.md @@ -1,29 +1,85 @@ # Platform Known Issues -Status: framework only. Detailed extraction not started. +Status: heavy support extraction pass started. ## Purpose -Track platform-specific known issues from code and support history. +Track platform-specific support patterns for SSN. This page combines current platform-agent pages with mined support history, but every support-derived item should be source-checked before becoming final user-facing documentation. ## Source Anchors -- `stevesbot/resources/learnings/social-stream-ninja-top-issues.md` -- `stevesbot/data/sqlite/knowledge.sqlite` -- `social_stream/sources/*` -- `ssapp/tests/tiktok/*` +- Current platform docs: `08-platform-sources/*.md` +- Current source targets: `social_stream/sources/*`, `social_stream/sources/websocket/*` +- App targets: `ssapp/main.js`, `ssapp/resources/electron-*-handler.js`, `ssapp/tiktok/*`, `ssapp/tiktok-signing/*`, `ssapp/tests/tiktok/*` +- Support mining: `11-support-kb/mining-method.md`, `historical-issues.md`, `unresolved-or-stale-claims.md` +- Support source anchors: `stevesbot/resources/learnings/social-stream-ninja-top-issues.md`, SSN Q&A exports, playbooks, and SQLite summary tables. -## Starter Notes +## First Checks For Any Platform -High-volume support areas include TikTok, YouTube, Kick, Twitch, Rumble, Facebook, and OBS display problems. Mark support-derived claims as historical until source-checked. +1. Identify surface: Chrome extension, standalone app Standard mode, standalone app WebSocket/API mode, external-browser flow, OBS overlay only, or custom/API source. +2. Confirm the source platform account/page is actually live or has active chat where required. +3. Confirm the exact page URL or username expected by the source. +4. Confirm the source is activated/reloaded after login or mode changes. +5. Confirm messages are appearing in the dock before debugging overlay display. +6. Confirm session ID matches source, dock, and overlay. +7. Ask for OS, app/extension version, browser, platform, connection mode, and screenshot/log/error text. -## Planned Sections +## Platform Matrix -- TikTok -- YouTube -- Kick -- Twitch -- Rumble -- Facebook -- Other platforms -- Historical/stale claims +| Platform | Support-derived symptoms | First checks | Verification needed | +| --- | --- | --- | --- | +| TikTok | Chat fails to connect, Standard and WebSocket disagree, messages/users missing, gift combo duplicates, long sessions stall or duplicate, regional/account verification changes. | Confirm live stream, username from profile URL, current SSN version, Standard vs WebSocket mode, page visibility for Standard, no VPN/session block, try re-auth/clear TikTok cookies if auth state is suspect. | Current TikTok source/app mode behavior, message-loss claims, gift aggregation/dedupe settings, regional age verification handling. | +| YouTube | Popout/Studio/live-chat page confusion, Google embedded sign-in blocked, auto-select/live-chat setting confusion, gifts/memberships/moderation events differ by mode, setup may require reload after going live. | Confirm popout/Studio/source path, extension vs app, Standard vs WebSocket, Google sign-in state, test message in active live chat, reload after login. | Gift support by mode, auto-select-live-chat setting path, moderation replay behavior, app OAuth fallback behavior. | +| Twitch | Source added but not activated, `Bad Request` or OAuth/token issues, channel points/subs/bans require specific modes/scopes, app OAuth callback ports may be occupied. | Press Activate, re-auth/remove/re-add if token state is bad, check IRC vs WebSocket/EventSub mode, check local port conflicts for app OAuth if callback fails. | EventSub scope matrix, port 8080/8181 current behavior, channel point/event payloads. | +| Kick | CAPTCHA/human verification loops, wrong browser profile during external login, chat unreliable until source is stopped/reactivated. | Try regular Chrome with extension, try WebSocket/external-browser mode when available, complete login in the right profile, stop and activate source after login. | Current Kick auth modes, event normalization, external-browser login flow, CAPTCHA handling limits. | +| Rumble | Verification loop, wrong popup/live URL, source only works after live starts or reactivation. | Verify current accepted URL shape, try popup/live URL from current source docs, activate only after live page/chat is ready, prefer extension if embedded login fails. | Current Rumble URL parser/source behavior; do not reuse old example IDs as generic instructions. | +| Facebook | User opens publisher/creator view instead of viewer view, chat dies when popup/source closes, embedded auth/session fragility. | Use viewer-facing live/chat context, confirm network/session state, try browser extension if app auth is blocked. | Current Facebook source requirements, mobile-data claim, app-vs-extension support. | +| Instagram | User needs live chat capture but login/page state is unclear. | Identify extension vs app and exact Instagram live URL/account; sign in in the active browser/session; test only while live. | Current Instagram source coverage and page requirements. | +| Discord | User enters a generic Discord URL instead of a channel URL, source not enabled/toggled, chat is expected from app/extension without page access. | Use full channel URL when needed, enable Discord source/toggle, confirm browser/session access. | Current Discord source setup and permission requirements. | +| Slack/WhatsApp/Telegram | Messages parsed/sent incorrectly or send queue fills input without submitting; platform pages require toggles. | Enable the platform-specific source/toggle, confirm web session and permissions, test manual send first. | Current source send/ACK behavior and parsing fixes. | +| X/Twitter | Source stops working after platform changes or auth/popup changes. | Confirm current support status, logged-in browser session, exact URL, and whether extension/app mode is supported. | Current X source viability and known-broken status. | +| LinkedIn | Own comments or some messages may not appear; beta extension was historically suggested. | Confirm current extension/app version, source page, and whether messages appear for other users. | Current LinkedIn source selectors and beta/current status. | +| Mixcloud | Chat historically stopped after 30-45 minutes and refresh restored it. | Refresh/reload as a temporary workaround if current source still behaves that way. | Current Mixcloud source and recent support reports. | +| Steam Broadcast | Users cannot find a normal popout chat URL. | Use current Quick Link/source instructions; support record mentioned Broadcast Chat quick link and Steam broadcast setup. | Current Steam source docs and source URL behavior. | +| VPZone | Source can reject channel casing or revert to generic channel. | Add from VPZone source button and verify username casing. | Current VPZone source code. | +| VK Video Live | Login error or incorrect URL in embedded flow. | Ask extension vs app and exact live URL; verify platform login page behavior. | Current VK source/auth support. | +| Beamstream | Historical blank capture/timing issues and source URL examples. | Verify current source URL syntax before use. | Current Beamstream source, timing fixes, and whether the platform is still supported. | + +## Cross-Platform Patterns + +### Extension vs Desktop App + +Support history repeatedly shows the Chrome extension works better when the platform depends on a real browser profile, cookies, or anti-bot checks. The desktop app is useful for integrated source windows and WebSocket/API flows, but embedded login can be blocked by Google, Kick, Rumble, and other protected sites. + +Doc rule: avoid saying "the app is easier" or "the extension is better" globally. Tie the recommendation to the platform and auth mode. + +### Standard vs WebSocket/API Modes + +Support history repeatedly shows mode confusion: + +- Standard/page-scrape modes can depend on page visibility, DOM changes, and browser throttling. +- WebSocket/API modes can be better for background operation but may expose different events, require scopes/auth, or miss platform-rendered messages. +- Some features such as sending, replies, channel points, memberships, gifts, or moderation events may be mode-specific. + +Doc rule: source pages should include a mode matrix for capture, send, events, gifts/donos, moderation, and background reliability. + +### Auth And Callback Problems + +Support records mention app OAuth callback port conflicts, wrong default browser profiles, and embedded-browser rejection. These need app-source verification before exact steps are documented. + +Doc rule: ask for exact error text and app/extension surface before prescribing. + +### Platform Breakage + +TikTok, X/Twitter, Kick, Rumble, and LinkedIn are historically volatile. Final docs should explain that platform-side changes can break integrations without over-promising repair timelines. + +## Source-Check Queue + +Prioritize these intense passes: + +1. TikTok: Standard vs WebSocket, app signing, visibility/background behavior, gift combos, reconnect/dedupe. +2. YouTube: Studio/popout/WebSocket setup, gifts, memberships, moderation events, Google sign-in fallback. +3. Twitch: Activate/auth, IRC vs EventSub/WebSocket, channel points, subscriptions, ban/timeout events, OAuth callback ports. +4. Kick: OAuth/CAPTCHA/external browser, WebSocket bridge, rewards/event payloads. +5. Rumble/Facebook/Instagram/Discord: exact URL/page requirements and extension/app differences. +6. Settings/auth pages: app browser data clearing, profile migration, extension update without uninstall. diff --git a/docs/agents/10-troubleshooting/settings-loss-and-backups.md b/docs/agents/10-troubleshooting/settings-loss-and-backups.md index 7f3d0155b..790324281 100644 --- a/docs/agents/10-troubleshooting/settings-loss-and-backups.md +++ b/docs/agents/10-troubleshooting/settings-loss-and-backups.md @@ -1,30 +1,220 @@ # Settings Loss And Backups -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started. ## Purpose Document settings loss, export/import, backup/restore, and app/extension storage differences. +This page is source-backed for the desktop app storage and backup paths. Extension settings still need a deeper current-source pass beyond the public docs and storage scans. + ## Source Anchors - `ssapp/state.js` +- `ssapp/main.js` - `ssapp/settings-backup.js` - `ssapp/transfer-backup.js` - `ssapp/transfer-restore-runner.js` -- `ssapp/tests/electron/settings-*.js` +- `ssapp/tests/electron/settings-transfer-e2e.js` +- `ssapp/tests/electron/settings-loss-diagnostics.js` +- `ssapp/tests/electron/settings-rootcause-diagnostics.js` +- `social_stream/README.md` - `social_stream/popup.js` +- `social_stream/service_worker.js` - `stevesbot/resources/instructions/social-stream-support.md` -## Starter Notes +## Storage Model + +### Desktop App + +Confirmed from `ssapp` source: + +- `state.js` persists app source/group/global state into browser `localStorage` under its persistence key, then also writes an older `settings` format for compatibility. +- `state.js` migrates old `localStorage.settings` data if the newer state has no sources yet. +- `main.js` maintains a cached Electron-side state object. +- `main.js` writes cached state to `savedSync.json` in the app user-data folder. +- `main.js` also uses `savedSync.json.bak`, electron-store cached-state backup, and `localStorageBackup`. +- `main.js` has quality/downgrade gates to avoid replacing good settings with a partial/empty settings payload. +- `main.js` can mirror cached state back into the main window `localStorage`. +- `settings-backup.js` exports recognized cached state fields plus selected app `localStorage` keys. + +Recognized desktop settings backup localStorage keys: + +- `socialStreamState` +- `settings` +- `betaMode` +- `youtubeAutoAdd` +- `youtubeAutoCleanup` +- `youtubeCheckInterval` +- `forceTikTokClassic` +- `preferTikTokLegacy` +- `tiktokModeExplicitlySelected` +- `lastTikTokMode` +- `language` + +### Chrome Extension + +Confirmed from public docs/support and initial source scans: + +- Extension state and settings use Chrome extension storage APIs and extension page state. +- The public README warns not to uninstall the extension when updating because uninstalling deletes settings. +- Manual extension update should replace files and reload the extension/browser instead. +- If uninstall is required, export settings first where possible. + +Needs deeper source verification: + +- Exact split between `chrome.storage.sync`, `chrome.storage.local`, popup state, and generated export files. +- Exact export/import UI labels and whether browser File System Access API restrictions affect the current export flow. + +## Backup Tools + +### File -> Settings Backup + +Source-backed: + +- Menu path exists under `File -> Settings Backup`. +- `Export Settings...` writes a JSON-like `.data` or `.json` file through `settings-backup.js`. +- Export includes recognized cached fields: `streamID`, `password`, `state`, and `settings`. +- Export can include selected local app settings, including source list state. +- Import reads the file, validates recognized Social Stream settings, restores cached state/localStorage keys, and reloads the main app window. +- `tests/electron/settings-transfer-e2e.js` exercises a settings export/import round trip and checks that unrecognized localStorage keys are excluded. + +Use this for: + +- Normal settings moves. +- Before switching app/source versions. +- Before risky troubleshooting. +- Before a user tries Full Reset. + +### Advanced Full Session Transfer + +Source-backed: + +- Menu path exists under `File -> Advanced Full Session Transfer`. +- It creates encrypted `.ssappbk` backups using the Electron user-data folder. +- Manual backup can exclude caches, which is recommended in the UI. +- Restore replaces local session data and creates a `pre-restore-*` copy beside the user-data folder. +- The app warns that normal settings moves should use Settings Backup instead. +- Auto Full Session Transfer can be configured with secure credential storage and runs only when sources are inactive/idle according to app runtime state. +- `tests/electron/settings-transfer-e2e.js` exercises full session backup/restore round trip logic. + +Use this for: + +- Whole-profile migration. +- Preserving cookies/session data and app profile state. +- Moving to another machine when normal settings export is not enough. + +Avoid this for: + +- Simple overlay styling changes. +- Simple source list cleanup. +- First-line troubleshooting when a smaller export/import is enough. + +## Reset And Recovery + +### Clear All Sources + +Source-backed: + +- Removes configured sources/groups from the embedded core. +- Keeps sessions, cookies, and other settings. + +Use when: + +- Source list is duplicated/corrupt. +- A source keeps auto-activating incorrectly. +- User wants to rebuild sources without wiping auth state. + +### Reset Everything / Full Reset + +Source-backed: + +- Shows a destructive warning. +- Clears store data, app localStorage keys, cache/cookies/storage for known sessions and partitions. +- Preserves stream ID and password where possible. +- Resets sessions to default. +- Reloads the main window. + +Use when: + +- App profile state is corrupt. +- Bad cookies/cache cause repeated login/source failures. +- The user explicitly wants a full reset and understands the consequence. + +Do not use when: + +- The user only needs to clear sources. +- The user has not exported settings and wants to keep configuration. + +## Settings Loss Diagnosis + +First classify the symptom: + +| Symptom | Likely area | First action | +| --- | --- | --- | +| Source list disappeared, but session ID/settings remain. | `socialStreamState` / state manager localStorage. | Check Settings Backup export and app user-data `savedSync.json`. | +| Global settings disappeared, but sources remain. | cached state/settings hydration or partial persistence. | Check whether `savedSync.json` still has settings; avoid full reset until backed up. | +| Everything reset after reinstall/update. | user-data or extension storage removed. | Ask whether app profile was deleted or extension was uninstalled. | +| Event Flow survived but other settings vanished. | storage split or stale support claim. | Source-check current Event Flow storage before stating cause. | +| Settings appear briefly then disappear. | hydration/race/partial-state issue. | Use diagnostics; collect logs and whether `savedSync.json` has settings. | + +Diagnostics source notes: + +- `settings-loss-diagnostics.js` checks app code signatures around popup hydration, synchronous `getSettings`, background `tryAgain`, and partial settings threshold. +- It interprets non-empty `savedSync` as evidence that symptoms may be hydration/IPC timing rather than true disk loss. +- `settings-rootcause-diagnostics.js` compares source paths, saved settings counts, fallback/core asset checks, and local backups. + +These diagnostics are supporting sanity checks, not full in-app testing. + +## User-Facing Recovery Flow + +1. Stop making changes. +2. Use `File -> Settings Backup -> Export Settings...` if the app still opens and has any useful settings left. +3. Check whether `savedSync.json` exists in the app user-data folder. +4. If there is a recent exported settings file, import it through `File -> Settings Backup -> Import Settings...`. +5. If restoring a whole app profile, use `Advanced Full Session Transfer -> Restore Full Session Transfer Backup...`. +6. If only sources are bad, use `Clear All Sources` instead of Full Reset. +7. Use Full Reset only after export/backup or when the user accepts total local cleanup. +8. After import/restore, reload/reactivate sources and reopen generated dock/overlay links. + +## Extension Update Guidance + +Source/public-doc-backed: + +- Do not uninstall the extension to update if settings should be kept. +- Replace the manual extension files and reload the extension/browser. +- Chrome Web Store updates are automatic but can lag manual builds. +- Export settings before uninstalling or switching extension channels where possible. + +Support reminders: + +- Browser cleanup tools, "clear on exit", profile resets, or Chrome profile changes can remove extension state. +- Session ID mismatch can look like settings loss because existing dock/overlay links point at a different session. + +## What To Ask For + +- Desktop app or extension? +- OS and app/extension version. +- Did the user update, uninstall, run cleanup tools, or reset browser/app data? +- Which settings vanished: source list, global settings, session ID, Event Flow, Spotify IDs, TTS, overlays? +- Does the app still show `File -> Settings Backup`? +- Was there a prior `.data`, `.json`, or `.ssappbk` backup? +- Does `savedSync.json` exist and have recent modified time? +- Was the user running a custom `--user-data-dir` / `SSAPP_USER_DATA_DIR`? + +## Source-Backed Facts To Keep Current -Support guidance says standalone app settings loss is recurring and can be caused by cleanup tools, AV, updates, or storage cleanup. Extension uninstalling can also delete settings. +- Normal backup file format marker: `ssapp-settings-backup`. +- Normal backup version: `1`. +- Full session backup file extension: `.ssappbk`. +- Full session restore keeps a `pre-restore-*` copy. +- Local-source ZIP extraction uses app user-data under `localSource`. +- The app has safeguards against partial settings downgrades. -## Planned Sections +## Open Verification Tasks -- Where settings live -- Export/import guidance -- App backup/restore -- Extension update without uninstalling -- Known failure causes -- Recovery steps +- Extension export/import exact UI and storage split. +- Event Flow storage location and why it may survive when other settings do not. +- Current user-data folder names per OS/build/package ID. +- Whether backup/import covers all newer settings added after this pass. +- Real in-app validation of export/import menu behavior. diff --git a/docs/agents/11-support-kb/common-questions.md b/docs/agents/11-support-kb/common-questions.md index 2dda48ac7..42c203ab0 100644 --- a/docs/agents/11-support-kb/common-questions.md +++ b/docs/agents/11-support-kb/common-questions.md @@ -1,31 +1,372 @@ # Common Support Questions -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started. This page is source-backed from current repo docs and should be expanded with mined Discord/KB history in later passes. -## Purpose +## Source Anchors -Collect common SSN support questions and source-backed answers. +- `README.md` +- `api.md` +- `parameters.md` +- `docs/commands.html` +- `docs/download.html` +- `docs/js/sites.js` +- `custom_sample.js` +- `custom_actions.js` +- `sample_wss_source.html` +- `docs/agents/08-platform-sources/*.md` +- Future support-mining pass: `C:\Users\steve\Code\stevesbot\data\sqlite\*.sqlite` -## Source Anchors +## Fast Reference Pages + +Use these cross-topic pages before repeating long answers: + +- `docs/agents/13-reference/commands-and-actions.md` +- `docs/agents/13-reference/url-parameters.md` +- `docs/agents/13-reference/modes-and-capability-matrix.md` +- `docs/agents/13-reference/free-paid-and-support-boundaries.md` +- `docs/agents/13-reference/custom-plugins-and-extensions.md` +- `docs/agents/13-reference/support-resources-and-escalation.md` +- `docs/agents/13-reference/settings-and-toggles.md` +- `docs/agents/13-reference/features-and-capabilities.md` + +## Product And Cost + +### Is Social Stream Ninja free? + +Yes. The core project is described as completely free and open-source. Most platform capture modes also avoid platform API keys, special permissions, or separate logins beyond the normal logged-in browser/app page. + +Important boundaries: + +- Third-party premium services can still cost money. This includes cloud TTS, some AI services, and platform services outside SSN. +- System TTS is free but can be harder to capture in OBS because browser pages may use the operating-system voice output. +- Donations to Steve are gifts. They are not payment for support, feature work, or guaranteed integrations. + +### Is it a Chrome extension or a standalone app? + +Both are supported product surfaces. + +- Browser extension: best when the user already has normal browser sessions, cookies, and site access working. It captures chat from supported web pages and popout chats through content scripts. +- Standalone desktop app: Electron app that loads Social Stream source files and manages source windows without requiring the extension. It can avoid some browser visibility/throttling problems and organize sources better, but some platform sign-in flows may block embedded browsers. +- Hosted/overlay pages: `dock.html`, `featured.html`, alert pages, games, API examples, and tool pages can be used with either surface as long as the session ID and transport settings match. + +If the extension and standalone app use the same session ID at the same time, do not assume both can publish/control the same workflow cleanly. For support, isolate one surface first. + +### Which version should users install? + +Common guidance: + +- Use the Chrome Web Store build for easiest install, but expect it to lag behind GitHub because store review takes time. +- Use manual GitHub install when the user needs the newest fixes or wants full source control. +- Use Firefox only when the missing features are acceptable. Firefox lacks some Chromium-only capabilities such as debugger/tab-capture behavior and some TTS/model support. +- Use the standalone app when users want managed source windows, always-on-top style workflows, or fewer problems from hidden/minimized browser windows. +- Use Lite only for quick/lightweight sessions. Current download docs describe Lite as having a very limited feature set and only a handful of core services. + +## Capture And Overlay Basics + +### Chat is not appearing. What should be checked first? + +Use the same first-pass checks before platform-specific debugging: + +1. Confirm SSN is enabled. In the extension, red means off and green means enabled. +2. Confirm the chat source page was reloaded after installing/reloading the extension. +3. Confirm the source page is a supported URL/mode. Many sites require popout chat, while some require the normal watch page. +4. Confirm the dock/overlay session ID matches the extension/app session ID. +5. Keep the source chat visible and not minimized. Browsers can throttle hidden or minimized pages. +6. Disable conflicting extensions or test in an isolated browser/incognito profile. +7. Confirm WebRTC/VDO.Ninja connectivity works in the browser/network. +8. For Discord, Slack, Telegram, WhatsApp, Google Meet, ChatGPT/static comments, and similar sensitive pages, confirm the required capture toggle is enabled. + +For platform-specific checks, start with: + +- `docs/agents/08-platform-sources/youtube.md` +- `docs/agents/08-platform-sources/tiktok.md` +- `docs/agents/08-platform-sources/twitch.md` +- `docs/agents/08-platform-sources/kick.md` +- `docs/agents/08-platform-sources/discord.md` + +### Overlay or dock is open but not updating. What usually causes it? + +Most common causes: + +- Session ID mismatch between source and page URL. +- The extension/app source is off, disconnected, or on a different session. +- Browser source in OBS is stale and needs a refresh. +- The wrong target label is being used. Pages can be labeled with `&label=NAME`, and API commands can target that label. +- The user opened a local page but expected hosted-page behavior, or opened the hosted page but expected a local `custom.js` file to load. +- API server toggles are not enabled for WebSocket/HTTP workflows. + +### Why does chat stop after a while or when hidden? + +Browser tabs/windows may throttle or stop JavaScript when minimized, hidden, discarded, or considered backgrounded. The README recommends keeping chat windows visible and active where possible. Even a small visible strip is often better than a minimized window. + +Support steps: + +- Do not minimize source chat windows. +- Keep chat scrolled to the newest messages. +- Check browser performance/background tab settings. +- Check `chrome://discards/` and turn off auto-discard for source pages. +- For Chromium, the README mentions disabling flags related to hidden cross-origin iframe throttling and native window occlusion when needed. +- Consider the standalone app for workflows that frequently hit browser throttling. + +## Installing And Updating + +### How do users manually install the extension? + +High-level flow: + +1. Download the current GitHub source archive. +2. Extract it to a folder. +3. Open the browser extensions page, such as `chrome://extensions/`. +4. Enable Developer Mode. +5. Load the extracted folder as an unpacked extension. +6. Reload chat pages after extension reload/install. + +Do not tell users to uninstall as an update method unless they have exported settings first. + +### How should users update without losing settings? + +Replace the extension files and reload the extension/browser. Do not uninstall, because uninstalling deletes extension settings. If uninstall is unavoidable, export settings first and import them after reinstalling. + +### Why does Manifest V2 show a warning? + +The README says the Manifest V2 warning can be ignored for current function. Manifest V3 builds exist through the Chrome Web Store and GitHub branches, but MV3 has restrictions and may require a small browser tab to stay open. + +## Platform Setup Answers + +### Which sites are supported? + +The README states 120+ sites, and `docs/js/sites.js` currently contains 139 named site entries. The repo source files and manifest are the more complete implementation inventory. + +The site metadata breaks down roughly as: + +- 100 standard/open-page entries +- 23 popout entries +- 9 toggle-required entries +- 4 WebSocket-source entries +- 3 manual-pick entries + +Always verify a specific site against the source file and manifest entry before promising exact support. + +### Can Social Stream Ninja do a specific feature? + +Usually the answer depends on mode, source, and setup. Start with `docs/agents/13-reference/features-and-capabilities.md`, then route to the exact feature page. + +High-level rules: + +- Core chat capture, dock, featured overlay, URL/CSS customization, API control, Event Flow, polls/waitlist/giveaway/games, and custom overlays are part of SSN. +- AI, cloud TTS, payment/donation services, and some platform API modes can require third-party accounts, keys, quotas, or costs. +- Two-way chat, moderation, richer events, and reward/gift coverage are platform/mode-specific. Check the platform doc before promising support. + +### Where is a setting or toggle? + +Start with `docs/settings.html` or `docs/agents/13-reference/settings-and-toggles.md`. + +Use this support pattern: + +1. Search the public settings reference for the setting name or behavior. +2. Confirm whether it is a persistent popup setting or a URL parameter. +3. If the user says it does not work, check whether the source page or overlay needs a reload. +4. Check whether another filter, opt-out, duplicate/relay, source toggle, or URL parameter is overriding the expected behavior. +5. Hide keys, webhooks, passwords, and session IDs in screenshots. + +### YouTube is not working. What should I ask? + +Ask which YouTube mode: + +- Live chat DOM mode: use the YouTube popout chat, studio chat, guest view, or a supported `live_chat` URL. +- YouTube watch page shortcut: the README mentions adding `&socialstream` to the YouTube link. +- Static comments: click the SS control on YouTube and manually select comments. +- WebSocket/API mode: requires source-page setup and is the better route for richer events. Some YouTube events require WebSocket mode and Google API permissions. + +Also check that the user reloaded the YouTube chat after extension reload and that permissions/auth are valid for sending chat or moderation actions. + +### TikTok is not working. What should I ask? + +Ask whether they are using extension capture or standalone/TikTok connector mode. + +- Extension capture requires the TikTok live chat page to remain visible/open. +- App/connector workflows may use additional signing, connection manager, or fallback behavior from the standalone app. +- Donation/gift/member fields vary by capture mode and by what TikTok exposes. + +Start with visibility, live status, account/session access, and whether the source page is being throttled. + +### Twitch is not working. What should I ask? + +Ask whether the user opened the Twitch popout chat. The README says Twitch requires popout chat to trigger extension capture. + +Also determine whether they are using: + +- DOM/popout mode +- WebSocket/source page mode +- Twitch IRC/WebSocket source +- Channel points/static helper scripts + +For richer event coverage, WebSocket mode may be required. + +### Kick is not working. What should I ask? + +Ask which Kick URL and mode: + +- Popout/chatroom page capture +- Source scout/static helper +- WebSocket source page +- Standalone app OAuth or WebSocket helper behavior + +Kick event coverage can depend on WebSocket mode. Check the Kick-specific agent doc before answering details. + +### Discord, Slack, Telegram, WhatsApp, Google Meet, or ChatGPT capture is not working. What is the common fix? + +Many sensitive/private-message surfaces require an explicit settings toggle before SSN injects or captures from them. Tell the user to enable the relevant source toggle, then reload the site. + +## Customization + +### How do users customize the overlay quickly? + +Common simple URL parameters: + +- `&lightmode` or `&darkmode` +- `&scale=1.5` +- `&compact` +- `&font=FONTNAME` +- `&speech=en-US` +- `&hidesource` +- `&showtime=10000` +- `&transparent` +- `&limit=100` + +For the full parameter inventory, see `parameters.md`. + +### How should users add custom CSS? + +Options: + +- Add CSS through the OBS browser-source custom CSS field. +- Use URL parameters such as `&css=...` or base64 CSS parameters. +- Use hosted/forked pages for durable custom templates. +- Use local pages on Windows when local-file behavior works for the workflow. + +The README notes OBS local-file CSS limitations on macOS/Linux. For those systems, prefer the OBS browser-source CSS field or hosted pages. + +### Can users build a custom overlay from scratch? + +Yes. The README points to `sampleoverlay` as a minimal HTML overlay. It can be used as a featured-message overlay or all-message dock alternative depending on the template mode. + +Use custom overlays when the user wants full layout/rendering control. Use URL parameters/CSS first when they only need styling changes. + +## Commands, API, And Automation + +### What built-in chat commands exist? + +Current public command docs list at least: + +- `!joke`: sends a random geeky dad joke when enabled. +- `hi`: welcomes users who say hi when enabled. +- `!cycle`: can cycle OBS scenes when OBS remote support and permissions are configured. + +Do not assume every command is enabled by default. Many command features require toggles in the extension/app settings or URL parameters. + +### How can StreamDeck or Companion control SSN? + +Enable remote API control, then use either: + +- HTTP GET commands such as `https://io.socialstream.ninja/SESSIONID/clearOverlay` +- WebSocket commands to `wss://io.socialstream.ninja/join/SESSIONID` +- Bitfocus Companion's Social Stream Ninja module + +Common actions include `clearOverlay`, `nextInQueue`, `autoShow`, `sendChat`, `sendEncodedChat`, poll controls, waitlist controls, and TTS controls. + +See `docs/agents/09-api-and-integrations/websocket-http-api.md` and `streamdeck-companion.md`. + +### How can an external app receive chat? + +Enable both: + +- `Enable remote API control of extension` +- `Send chat messages to API server` + +Then connect to channel 4: + +```text +wss://io.socialstream.ninja/join/SESSION_ID/4 +``` + +Chat messages normally include `chatname`, `chatmessage`, and `type`. + +### Are donation webhooks secure? + +Treat webhook URLs and session IDs as secrets. The API docs state webhook URLs do not use signature verification, so anyone with the session ID/webhook URL can send fake donation events. + +Supported webhook paths documented in `api.md` include Stripe, Ko-Fi, Buy Me A Coffee, and Fourthwall. + +## TTS And AI + +### Which TTS options are free? + +- System/browser TTS is free but harder to capture in OBS because it may play through system audio. +- Kokoro is described in README as browser-based free/premium-quality TTS but can require a powerful computer. +- Cloud providers such as Google Cloud, ElevenLabs, Speechify, Gemini, and OpenAI-compatible endpoints may require accounts, keys, paid usage, or local hosting depending on provider. + +### Does SSN support AI? + +Yes. Public docs mention Ollama/local AI and premium AI services for chatbot/moderation/cohost workflows. AI features are optional and depend on settings, local model availability, or API keys. + +When answering exact provider/setup questions, check `docs/commands.html`, `docs/agents/09-api-and-integrations/ai-features.md`, and the current settings definitions/code. + +## Custom Plugins, Scripts, And New Integrations + +### Can users make their own plugin? + +The public wording says SSN has scriptable plugin/custom logic support, but for support answers be precise: + +- There is no single packaged "plugin marketplace" flow documented for normal users. +- Users can customize behavior with URL parameters, CSS, custom overlays, API integrations, `custom.js`, uploaded custom user functions, and custom sources. +- Developers can add a real source by adding a content script/source file and manifest entries. + +### What is `custom.js`? + +`custom_sample.js` can be renamed to `custom.js`. It is for local dock/featured-page behavior such as `applyCustomActions(data)` and `applyCustomFeatureActions(data)`. + +Important limitation: the sample says the local file path must be used for the dock to load local `custom.js`. Hosted `https://socialstream.ninja/dock.html` will not load a local `custom.js`. + +### What is `custom_actions.js`? + +`custom_actions.js` is an uploaded custom user-function template. It defines: + +```javascript +window.customUserFunction = function(data) { + return data; +}; +``` + +When custom JS is enabled, the background processing path calls `customUserFunction(data)`. Returning modified data continues processing; returning `false` can block a message in the template examples. + +### Can users request a new site? + +Yes, through GitHub issues or Discord. The README says requests are not guaranteed. Steve generally prioritizes publicly accessible social chat sites with meaningful communities, but support can be declined or left to forks when legal, quality, or maintenance concerns exist. Steve does not accept payment for adding integrations or support. + +## Support Etiquette And Escalation + +### Where should users get support? + +The public support path is Discord: + +```text +https://discord.socialstream.ninja +``` -- `stevesbot/resources/learnings/social-stream-ninja-top-issues.md` -- `stevesbot/resources/learnings/support-qa/social-stream-qa.md` -- `stevesbot/resources/learnings/support-qa/social-stream-qa-expanded.md` -- `stevesbot/data/sqlite/stevesbot.sqlite` -- `stevesbot/data/sqlite/knowledge.sqlite` +The README names `#chat.overlay-support` for free support. GitHub issues are also appropriate for bugs and feature requests. -## Starter Notes +### What should an agent collect before escalating? -This should become a practical agent FAQ, but every answer should be checked against current code/docs before being treated as current. +Collect: -## Planned Sections +- Surface: extension, standalone app, hosted page, local page, Lite. +- Browser/app version and install path. +- Session ID match confirmation, but do not ask for a private session ID unless necessary. +- Platform/source URL pattern and whether it is popout, standard, toggle-required, manual, or WebSocket mode. +- Relevant toggles enabled. +- OBS/browser-source URL when the problem is overlay display. +- Console errors or screenshots, if available. +- Whether the source works in a clean browser profile. -- Capture not working -- Overlay not updating -- Auth/sign-in -- TikTok -- YouTube -- Kick -- TTS -- Settings loss -- Customization +Do not promise fixes for platform breakages without checking current code/issues, because supported sites can change or break when third-party platforms change. diff --git a/docs/agents/11-support-kb/historical-issues.md b/docs/agents/11-support-kb/historical-issues.md index 188769c5a..88b22d39e 100644 --- a/docs/agents/11-support-kb/historical-issues.md +++ b/docs/agents/11-support-kb/historical-issues.md @@ -1,25 +1,314 @@ # Historical Support Issues -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started. ## Purpose -Track issues seen in support history that may no longer apply, or that need current-source verification. +This file tracks recurring SSN support issues found in historical support summaries, playbooks, Q&A exports, and SQLite summary tables. It is not a final troubleshooting page. It is a mined evidence map for future docs and source verification. + +Use `10-troubleshooting/platform-known-issues.md` for the platform-facing matrix and `unresolved-or-stale-claims.md` for claims that should not be promoted yet. ## Source Anchors +- `stevesbot/resources/instructions/social-stream-support.md` - `stevesbot/resources/learnings/social-stream-ninja-top-issues.md` +- `stevesbot/resources/learnings/unresolved-analysis.md` +- `stevesbot/resources/learnings/pipeline-analysis.md` +- `stevesbot/resources/learnings/playbooks/playbook-obs-overlay-issues.md` +- `stevesbot/resources/learnings/playbooks/playbook-tiktok-connection.md` +- `stevesbot/resources/learnings/support-qa/social-stream-configuration.md` +- `stevesbot/resources/learnings/support-qa/social-stream-qa.md` +- `stevesbot/resources/learnings/support-qa/social-stream-qa-expanded.md` - `stevesbot/data/sqlite/knowledge.sqlite` -- `stevesbot/data/sqlite/archive.sqlite` +- `stevesbot/data/sqlite/stevesbot.sqlite` + +## High-Volume Categories + +### Source Opens But Messages Are Blank + +Status: support-derived, needs current source verification per platform. + +Repeated symptoms: + +- Chat source opens but no messages appear in the dock or overlay. +- User is on the wrong page shape: full stream page instead of popout chat, creator/publisher view instead of viewer view, Studio page with a different DOM, or platform-specific URL mismatch. +- Capture tab/window is hidden, minimized, backgrounded, or throttled. +- User has not pressed `Activate` after adding or signing into a source. +- Extension is disabled, missing site permission, or conflicted by another extension/ad blocker/privacy tool. + +Historical support actions: + +- Confirm the extension icon is enabled/green. +- Confirm the exact session ID matches source, dock, and overlay. +- Use platform popout chat where the source expects popout. +- Reload/re-activate after login or CAPTCHA completion. +- Test in a clean Chrome profile or incognito window with only SSN enabled. +- Compare with another platform to separate platform-specific failure from general SSN setup failure. + +Docs impact: + +- Keep in `10-troubleshooting/extension-not-capturing.md`. +- Add platform-specific URL/page-shape notes to each source page. +- Do not claim all platforms require popout chat; current source pages differ. + +### Embedded-Browser Auth Fails + +Status: support-derived, volatile-platform. + +Repeated symptoms: + +- Google, Twitch, Kick, Rumble, LinkedIn, Zoom, Slack, Facebook, or other protected sites reject the standalone app's embedded browser. +- User sees "browser not supported", CAPTCHA/verification loops, Cloudflare-like anti-bot pages, missing popup state, or failed cookie persistence. +- The same site works in a normal browser or with the Chrome extension. + +Historical support actions: + +- Prefer the Chrome extension for sites that depend on an existing browser session. +- Use an external-browser or WebSocket flow when the app offers one. +- After sign-in, stop and activate the source again. +- Clear browser data only when a stale embedded session is suspected. +- Avoid promising that embedded login will work for every protected site. + +Docs impact: + +- Add an `auth-and-sign-in.md` troubleshooting pass later. +- Mark platform support as mode-dependent: extension, app Standard, app WebSocket, API/EventSub, or external browser. + +### TikTok Mode And Stability Issues + +Status: support-derived, volatile-platform, needs current source verification. + +Repeated symptoms: + +- TikTok worked before and suddenly stops. +- Standard mode requires the live page/capture page to stay visible or active. +- WebSocket mode works in the background but may miss some messages/users. +- Some regions, age verification flows, new accounts, VPNs, or TikTok anti-bot state affect capture. +- Gift combos appear as multiple incremental messages. +- Long sessions can stall, duplicate, or queue messages. + +Historical support actions: + +- Confirm the creator is currently live. +- Use the username from `tiktok.com/@USERNAME`, not the display name. +- Try Standard and WebSocket modes separately. +- Update SSN before debugging deep TikTok breakage. +- Re-auth, clear TikTok cookies, or try a clean browser profile when auth/session state is suspect. +- Treat gift combo updates as TikTok-side behavior unless current code says aggregation is available. + +Docs impact: + +- Keep TikTok guidance cautious and date-sensitive. +- Add a current-code pass through `ssapp/tiktok/*`, `ssapp/tiktok-signing/*`, `ssapp/tests/tiktok/*`, and `social_stream/sources/tiktok.js`. + +### YouTube Setup, Studio, Gifts, And Moderation Events + +Status: support-derived, partially source-backed from existing YouTube page pass. + +Repeated symptoms: + +- User opens a YouTube page but not the right chat view. +- Popout vs Studio vs WebSocket mode confusion. +- "Go live, trigger fake message, reload" style workflows take minutes. +- Auto-select/live-chat behavior was mentioned historically for Standard mode. +- YouTube gifts/memberships and moderation events can appear differently across capture paths. +- Google sign-in is blocked in embedded app contexts. + +Historical support actions: + +- Use popout chat or Studio-supported capture paths as documented by current source. +- If Google embedded sign-in fails, use browser extension or WebSocket/external-browser flow where available. +- Reopen/reload capture after login or mode changes. +- Verify whether gifts/memberships are supported in both Standard and WebSocket modes for the current build before documenting. + +Docs impact: + +- Add a YouTube intense pass for gifts, moderation replay, auto-select-live-chat, and app OAuth behavior. + +### Twitch Activation, OAuth, And EventSub + +Status: support-derived, needs current source verification for scopes/events. + +Repeated symptoms: + +- Twitch source added but not activated. +- "Bad Request" or token/auth failures. +- Channel points, subs, raids, bans, or other events require different modes/scopes than normal chat. +- Desktop app OAuth can fail if callback ports are blocked. + +Historical support actions: + +- Press `Activate` for Twitch after adding/signing in. +- Re-authenticate or remove/re-add source if token state is bad. +- Try WebSocket/EventSub mode when IRC/basic chat mode does not expose an event. +- Check local ports 8080 and 8181 if app OAuth callback fails. + +Docs impact: + +- Add source-backed Twitch mode matrix: chat, send, channel points, subs, user bans/timeouts, and required auth. + +### Kick, Rumble, And CAPTCHA/Verification Loops + +Status: support-derived, volatile-platform. + +Repeated symptoms: + +- Kick or Rumble sign-in gets stuck at human verification/CAPTCHA. +- Embedded browser fails while a regular browser can sign in. +- Kick external-browser login may open in the wrong browser profile. +- Users need to stop/re-activate after completing sign-in. + +Historical support actions: + +- Use Chrome extension when app embedded login is blocked. +- Try app WebSocket/external-browser mode if available. +- Copy the external-browser login URL into the browser profile where the correct account is signed in. +- Re-activate the source after successful login. + +Docs impact: + +- Source-check current Kick and Rumble implementations before finalizing exact steps. + +### OBS Overlay Blank, White, Or Not Updating + +Status: support-derived, partially source-backed from overlay/OBS pages. + +Repeated symptoms: + +- `featured.html` looks white/blank in Chrome but is transparent in OBS. +- `dock.html` is confused with the overlay page. +- Overlay URL has the wrong session ID or wrong page. +- Messages show in dock but not overlay. +- OBS browser source dimensions, cache, or refresh state prevent display. +- User expects dock setting changes to automatically alter an already-open overlay without reopening/refreshing the generated link. + +Historical support actions: + +- Distinguish dock/control page from overlay/display page. +- Confirm `?session=` matches exactly. +- Open overlay URL in a normal browser before debugging OBS. +- Feature a message manually or use `&autoshow`. +- Refresh or recreate OBS browser source when the browser engine caches bad state. +- Reopen generated links after settings that are encoded in URL parameters. + +Docs impact: + +- Keep in `10-troubleshooting/obs-overlay-display.md`. +- Add source-backed mapping of dock settings that change stored state vs URL parameters vs per-page local state. + +### Text Is Invisible Or Styling Does Not Apply + +Status: support-derived, partially source-backed. + +Repeated symptoms: + +- White text on white/transparent background. +- Custom OBS CSS conflicts with SSN theme CSS. +- Streamlabs CSS snippets do not map directly to SSN classes/variables. +- Ticker/horizontal scroll messages wrap unexpectedly. +- Donation/member highlight colors are not distinct enough. + +Historical support actions: + +- Inspect background and text color settings first. +- Use built-in themes or documented CSS variables before arbitrary CSS. +- Reopen overlay/dock link when generated URL parameters changed. +- Use CSS variables and source-specific classes only after source-checking current class names. + +Docs impact: + +- Add a custom overlay/CSS heavy pass later. +- Move exact class/variable lists into current-source-backed docs only. + +### TTS Audio Missing, Intermittent, Or Wrong Device + +Status: support-derived, partially source-backed from TTS page. + +Repeated symptoms: + +- Browser-native/system TTS plays on the wrong output device or not in OBS. +- OBS Browser Source audio is not routed because "Control Audio via OBS" is off or the page has not been interacted with. +- Cloud TTS drops due to provider/API rate limits or key restrictions. +- Queue overflow drops messages when chat arrives faster than speech playback. +- Local/custom TTS endpoints historically had build-specific bugs. + +Historical support actions: + +- Test TTS in a normal browser outside OBS. +- Click/interact with the page to satisfy autoplay requirements. +- Use OBS audio controls or a virtual audio cable when needed. +- Check provider credentials and restrictions. +- Use current/beta build only if a known fix is verified. + +Docs impact: + +- Add provider-by-provider source verification. +- Avoid claiming local/cloud provider support without checking current provider menu and code. + +### Settings Loss, Migration, And Backups + +Status: support-derived, needs source verification. + +Repeated symptoms: + +- Some app settings are lost after restart/update/cleanup, while sources or Event Flow settings survive. +- Users uninstall the extension to update and lose extension storage. +- Migration from Web Store extension to manual extension or desktop app loses settings. +- New machine transfer is unclear. + +Historical support actions: + +- Do not uninstall the Chrome extension just to update. +- Export settings before switching builds or machines when an export option exists. +- Keep critical session IDs, overlay URLs, API keys, and Event Flow notes backed up separately. +- Check app user-data/localStorage paths for desktop backups before documenting exact paths. + +Docs impact: + +- Needs heavy pass through `ssapp/state.js`, app storage, extension storage/export code, and current settings UI. + +### Release Channel And Version Confusion + +Status: support-derived. + +Repeated symptoms: + +- Chrome Web Store lag vs GitHub/manual build. +- Users are on older app versions with known fixed bugs. +- Platform-specific breakages require beta or latest release. +- Users cannot tell whether app/extension/source files are current. + +Historical support actions: + +- Ask for exact SSN version, app vs extension, OS, browser, platform source, and connection mode. +- For app bugs, ask whether the build loads local Social Stream source or bundled/remote source. +- For extension bugs, ask whether Web Store or manual GitHub build is installed. + +Docs impact: + +- Keep install/update docs separated by surface. +- Add a "reporting checklist" to final support docs. + +## Newer Curated Support Records To Source-Check -## Starter Notes +Recent `stevesbot.sqlite` summaries mention these items. Treat them as candidates, not final facts: -Platform behavior changes frequently. A support answer that was right for an older SSN version or platform API may be wrong now. +| Topic | Historical support summary | Verification target | +| --- | --- | --- | +| Twitch OAuth callback ports | Desktop app Twitch WebSocket OAuth can fail when local ports 8080/8181 are occupied. | `ssapp` OAuth/server handlers. | +| Close to Tray/start minimized | Desktop app supports Close to Tray and startup flags. | `ssapp/main.js`, window/menu/tray handling. | +| Profiles | Global Settings profiles can save and switch overlay configurations. | current settings UI/storage code. | +| Fixed messages at intervals | Global Settings can send fixed chat messages on a timer. | settings/action code. | +| Horizontal ticker | Horizontal Scroll preset or ticker toggles control ticker layout. | overlay/theme/settings code. | +| YouTube gifts | Gifts supported in Standard and WebSocket modes in a recent build. | YouTube source and WebSocket source code. | +| Local Kokoro/custom TTS | Local TTS endpoint fixes landed in beta. | TTS provider code/current docs. | +| VPZone source | VPZone username casing and source button behavior. | VPZone source code. | +| `user_banned` event | Beta event stream exposes ban/timeout metadata for Twitch/Kick/YouTube. | event schema/source emitters. | +| YouTube translations | Captured translations can come from YouTube creator/platform settings. | YouTube source and UI docs. | -## Planned Sections +## Open Extraction Gaps -- Version-specific issues -- Platform-side breakages -- Fixed bugs -- Stale setup instructions -- Claims needing source verification +- Raw archive frequency checks have not been performed beyond schema/count inspection. +- `resources/knowledge.sqlite` has not been schema-checked in this pass. +- Many support answers reference older SSN versions such as `v0.3.127` or `v0.3.128`; current behavior must be checked against source before final docs. +- Exact settings labels, paths, CSS class names, and provider menus need current UI/source verification. diff --git a/docs/agents/11-support-kb/mining-method.md b/docs/agents/11-support-kb/mining-method.md index 9ef0cde54..87d98405d 100644 --- a/docs/agents/11-support-kb/mining-method.md +++ b/docs/agents/11-support-kb/mining-method.md @@ -1,27 +1,204 @@ # Support KB Mining Method -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started. ## Purpose -Document how to mine `stevesbot` support data safely and usefully for SSN docs. +This file explains how future agents should mine `C:\Users\steve\Code\stevesbot` for Social Stream Ninja documentation without re-processing the same files, leaking unrelated/private data, or promoting stale support advice into current docs. -## Source Anchors +The support archive is evidence of real user problems. Current `social_stream` and `ssapp` source files remain the source of truth for how SSN works today. -- `stevesbot/resources/instructions/social-stream-support.md` -- `stevesbot/resources/learnings/**` -- `stevesbot/data/sqlite/*.sqlite` -- `stevesbot/data/mined-threads/*.jsonl` +## Safety Boundary -## Starter Notes +Write only inside `C:\Users\steve\Code\social_stream\docs\agents`. -Prefer curated and summarized data before raw Discord archive data. Treat support material as evidence and current code as source of truth. +Read support data in this order: -## Planned Sections +1. Current SSN source/docs in `social_stream` and `ssapp`. +2. Curated SSN support instructions and generated summaries in `stevesbot/resources`. +3. Curated SQLite summary tables. +4. Raw archive/message tables only when a summarized source is insufficient. -- Safe source order -- SQLite query units -- Filtering SSN from unrelated products -- Anonymization rules -- Historical claim handling -- Pass logging +Do not broad-search `stevesbot/resources` without excluding `resources/secrets`. Prefer known safe paths listed below. Do not copy raw user conversations into docs. Summarize symptoms, advice, and verification targets instead. + +## Safe Source Set + +Curated instruction files: + +| Source | Use | Extraction status | +| --- | --- | --- | +| `resources/instructions/social-stream-support.md` | Support stance, first-response checks, platform caveats, escalation style. | heavy-started | +| `resources/instructions/drafter-context.md` | Bot drafting context and product boundaries. | quick-started | + +Curated learning files: + +| Source | Use | Extraction status | +| --- | --- | --- | +| `resources/learnings/social-stream-ninja-top-issues.md` | Top recurring support themes from summarized threads. | heavy-started | +| `resources/learnings/unresolved-analysis.md` | Unresolved pattern clusters and possible product/doc gaps. | heavy-started | +| `resources/learnings/pipeline-analysis.md` | Support-bot confidence gaps and missing KB areas. | heavy-started | +| `resources/learnings/cross-product-integration-guide.md` | OBS, VDO.Ninja, Electron Capture, and SSN boundary confusion. | heavy-started | +| `resources/learnings/playbooks/playbook-obs-overlay-issues.md` | OBS/browser-source and overlay triage. | heavy-started | +| `resources/learnings/playbooks/playbook-tiktok-connection.md` | TikTok mode and breakage triage. | heavy-started | +| `resources/learnings/playbooks/triage-macros.md` | Reusable triage branches for SSN/OBS/TikTok. | quick-started | +| `resources/learnings/support-qa/social-stream-configuration.md` | Setup and configuration Q&A. | heavy-started | +| `resources/learnings/support-qa/social-stream-qa.md` | Broad SSN Q&A. | heavy-started | +| `resources/learnings/support-qa/social-stream-qa-expanded.md` | Expanded SSN Q&A. | heavy-started | + +SQLite databases: + +| Source | Tables checked | Use | Extraction status | +| --- | --- | --- | --- | +| `data/sqlite/knowledge.sqlite` | `mined_threads`, FTS tables | Thread-level summaries, categories, products, platforms, issue frequency. | heavy-started | +| `data/sqlite/stevesbot.sqlite` | `support_records`, `qa_entries` | Curated support records and generated Q&A entries. | heavy-started | +| `data/sqlite/archive.sqlite` | `archived_messages`, FTS tables | Raw archived messages for final confirmation only. | quick-started | +| `resources/knowledge.sqlite` | not yet schema-checked in this pass | Older/alternate knowledge DB if needed. | not-started | + +Avoid backups unless a current DB is missing or corrupted. + +## Database Shapes + +Observed schemas: + +`knowledge.sqlite`: + +- `mined_threads`: `thread_id`, `thread_name`, `channel_name`, `source_url`, date fields, counts, `summary`, `problem_statement`, `solution`, `resolved`, JSON product/platform/error fields, `category`, `searchable_text`. +- Count checked: 2,264 mined threads. + +`stevesbot.sqlite`: + +- `support_records`: `route_id`, `product_id`, thread reference, date range, `question_summary`, `answer_summary`, `status_flags`, `searchable_text`. +- Count checked: 499 support records. +- Product counts checked: `social-stream-support` 180, `social-stream` 24, plus other non-SSN products. +- `qa_entries`: `question_text`, `answer_text`, support/repo refs, confidence. +- Count checked: 358 Q&A entries. + +`archive.sqlite`: + +- `archived_messages`: raw `content`, author/thread/channel fields, timestamps, source URL. +- Count checked: 47,600 archived messages. +- Use only for anonymized confirmation of symptom language or frequency. + +## Query Recipes + +Use these patterns from `C:\Users\steve\Code\ssapp` or any shell where `sqlite3.exe` resolves: + +```powershell +sqlite3.exe C:\Users\steve\Code\stevesbot\data\sqlite\knowledge.sqlite ".schema mined_threads" +sqlite3.exe C:\Users\steve\Code\stevesbot\data\sqlite\knowledge.sqlite "select count(*) from mined_threads;" +sqlite3.exe C:\Users\steve\Code\stevesbot\data\sqlite\stevesbot.sqlite "select product_id, count(*) from support_records group by product_id order by count(*) desc;" +``` + +Product-filtered term count: + +```sql +with terms(term) as ( + values ('TikTok'),('YouTube'),('Twitch'),('Kick'),('Rumble'),('Facebook'), + ('Instagram'),('OBS'),('TTS'),('dock.html'),('featured.html'), + ('WebSocket'),('OAuth'),('settings'),('CSS'),('Electron'), + ('Chrome Extension'),('Desktop App') +) +select term, + (select count(*) + from mined_threads + where products_json like '%Social Stream%' + and searchable_text like '%' || term || '%') as mined_threads +from terms +order by mined_threads desc; +``` + +Curated support-record sample: + +```sql +select product_id, + status_flags, + substr(question_summary, 1, 180), + substr(answer_summary, 1, 220) +from support_records +where product_id like 'social-stream%' +order by date_end desc +limit 25; +``` + +## First-Pass Frequency Results + +`knowledge.sqlite` mined thread term counts for `products_json like '%Social Stream%'`: + +| Term | Count | +| --- | ---: | +| Desktop App | 357 | +| Twitch | 295 | +| YouTube | 294 | +| settings | 293 | +| OBS | 278 | +| TikTok | 240 | +| WebSocket | 235 | +| dock.html | 180 | +| Kick | 138 | +| Chrome Extension | 122 | +| TTS | 68 | +| Facebook | 55 | +| Rumble | 46 | +| CSS | 40 | +| featured.html | 34 | +| Electron | 27 | +| Instagram | 25 | +| OAuth | 10 | + +`stevesbot.sqlite` support-record term counts for `product_id like 'social-stream%'`: + +| Term | Count | +| --- | ---: | +| WebSocket | 36 | +| YouTube | 33 | +| Twitch | 31 | +| settings | 27 | +| TikTok | 25 | +| OBS | 24 | +| dock.html | 16 | +| Desktop App | 16 | +| Kick | 14 | +| Chrome Extension | 13 | +| Facebook | 9 | +| TTS | 9 | +| Electron | 9 | +| Instagram | 8 | +| featured.html | 8 | +| CSS | 8 | +| OAuth | 7 | +| Rumble | 5 | + +These counts are only rough indicators because one thread can mention many terms. + +## Extraction Levels + +Quick extraction: + +- List the file/table and its purpose. +- Capture product filters, schema, and candidate terms. +- Record whether the source is curated, generated, raw, or mixed-product. + +Heavy extraction: + +- Extract repeated symptoms, setup mistakes, workarounds, and support wording. +- Separate SSN extension, SSN desktop app, OBS/browser source, and unrelated VDO.Ninja issues. +- Link each claim to a source family: current repo, curated support docs, SQLite summary, or raw archive. +- Move risky claims into `unresolved-or-stale-claims.md`. + +Intense extraction: + +- For high-volume or fragile areas, verify each support claim against current code/docs. +- Use raw archive only for anonymized frequency/symptom confirmation. +- Produce final-grade troubleshooting pages with current-version caveats. + +## Claim Handling Rules + +Use these labels while drafting: + +- `current-source-backed`: verified in current `social_stream` or `ssapp` source/docs. +- `support-derived`: seen in support history but not yet source-checked. +- `historical`: tied to an older version, older platform state, or generated support output. +- `volatile-platform`: likely to change outside SSN control. +- `needs-verification`: do not promote to final user-facing docs yet. + +Support material often contains old version numbers, stale UI names, and generated prose. Keep the user problem and troubleshooting shape, but re-check final wording against current source before presenting as current behavior. diff --git a/docs/agents/11-support-kb/support-source-map.md b/docs/agents/11-support-kb/support-source-map.md index 9719274b5..7fbddba2e 100644 --- a/docs/agents/11-support-kb/support-source-map.md +++ b/docs/agents/11-support-kb/support-source-map.md @@ -1,6 +1,6 @@ # Support Source Map -Status: framework only. Detailed extraction not started. +Status: framework plus repo-backed FAQ baseline and first historical support-mining pass. ## Purpose @@ -18,11 +18,44 @@ Map each `stevesbot` support source to the kind of SSN documentation it can info The useful support sources are mixed with unrelated product material. This page should keep the SSN-relevant support map explicit. -## Planned Sections - -- Curated support instructions -- Generated issue summaries -- Q&A exports -- Playbooks -- SQLite tables -- Raw transcript/archive usage +`common-questions.md` now contains a repo-backed support baseline from current public docs, API docs, parameter docs, custom script templates, site metadata, and platform agent pages. It should not be treated as mined support history yet. + +Historical support mining has started in `mining-method.md`, `historical-issues.md`, `unresolved-or-stale-claims.md`, and `10-troubleshooting/platform-known-issues.md`. Support-derived facts remain secondary to current source. + +## Current Baseline Outputs + +- `common-questions.md`: current repo-backed FAQ and triage answers. +- `10-troubleshooting/quick-triage.md`: first-response support flow. +- `08-platform-sources/*.md`: platform-specific setup/support notes for extracted platforms. +- `mining-method.md`: safe support-mining method, DB schemas, counts, query recipes, and first term-frequency tables. +- `historical-issues.md`: recurring support categories and candidate docs impact. +- `unresolved-or-stale-claims.md`: claim register for old, volatile, or unverified advice. +- `10-troubleshooting/platform-known-issues.md`: platform support matrix. + +## Source Map + +| Source | Type | SSN value | Current status | +| --- | --- | --- | --- | +| `stevesbot/resources/instructions/social-stream-support.md` | curated support instruction | Current support style, first checks, escalation guidance, platform caveats. | heavy-started | +| `stevesbot/resources/instructions/drafter-context.md` | curated bot context | Product boundary and drafting context. | quick-started | +| `stevesbot/resources/learnings/social-stream-ninja-top-issues.md` | generated support summary | Top recurring SSN issues from summarized support threads. | heavy-started | +| `stevesbot/resources/learnings/unresolved-analysis.md` | generated unresolved summary | Repeated unresolved categories and possible product/doc gaps. | heavy-started | +| `stevesbot/resources/learnings/pipeline-analysis.md` | support-bot analysis | Missing KB areas and confidence-gap notes. | heavy-started | +| `stevesbot/resources/learnings/cross-product-integration-guide.md` | generated playbook | Product boundaries: VDO.Ninja, SSN, OBS, Electron Capture. | heavy-started | +| `stevesbot/resources/learnings/playbooks/playbook-obs-overlay-issues.md` | playbook | OBS/browser-source and SSN overlay triage. | heavy-started | +| `stevesbot/resources/learnings/playbooks/playbook-tiktok-connection.md` | playbook | TikTok mode and breakage triage. | heavy-started | +| `stevesbot/resources/learnings/playbooks/triage-macros.md` | macros | Reusable support branches for TikTok and blank overlays. | quick-started | +| `stevesbot/resources/learnings/support-qa/social-stream-configuration.md` | Q&A export | Setup/install/configuration and parameter reminders. | heavy-started | +| `stevesbot/resources/learnings/support-qa/social-stream-qa.md` | Q&A export | Broad historical SSN questions and answers. | heavy-started | +| `stevesbot/resources/learnings/support-qa/social-stream-qa-expanded.md` | Q&A export | Expanded historical platform and feature Q&A. | heavy-started | +| `stevesbot/data/sqlite/knowledge.sqlite` | SQLite summary DB | 2,264 mined threads with product/category/platform fields and summaries. | heavy-started | +| `stevesbot/data/sqlite/stevesbot.sqlite` | SQLite curated support DB | 499 support records and 358 generated Q&A entries. | heavy-started | +| `stevesbot/data/sqlite/archive.sqlite` | SQLite raw archive DB | 47,600 archived messages for anonymized confirmation only. | quick-started | +| `stevesbot/resources/knowledge.sqlite` | SQLite DB | Alternate/older knowledge store. | not-started | + +## Pending Support Mining + +- Deep-query high-frequency SQLite topics by platform/mode after current source pages are expanded. +- Source-check stale claims before moving them into final docs. +- Use raw archive only for anonymized frequency confirmation. +- Add file-level source links after intense passes through specific source files. diff --git a/docs/agents/11-support-kb/unresolved-or-stale-claims.md b/docs/agents/11-support-kb/unresolved-or-stale-claims.md index d7879549f..18a5471a4 100644 --- a/docs/agents/11-support-kb/unresolved-or-stale-claims.md +++ b/docs/agents/11-support-kb/unresolved-or-stale-claims.md @@ -1,26 +1,68 @@ # Unresolved Or Stale Claims -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started. ## Purpose -Track claims that should not be promoted into final docs until verified. +Use this as the holding area for support-derived claims that are useful but risky. A claim belongs here when it is old, platform-volatile, generated by a support bot, version-specific, or not yet checked against current source. -## Source Anchors +Do not promote these claims into final user-facing docs without source verification. -- `stevesbot/resources/learnings/unresolved-analysis.md` -- `stevesbot/resources/learnings/social-stream-ninja-top-issues.md` -- `stevesbot/data/sqlite/knowledge.sqlite` -- Current SSN source files +## Claim Register -## Starter Notes +| Claim | Source family | Risk | Verification target | Current doc handling | +| --- | --- | --- | --- | --- | +| TikTok changes its API/DOM every 2-4 weeks. | support instructions, TikTok playbook, Q&A exports | Pattern may remain true but exact cadence can become stale. | current issue/release history and source churn. | Say TikTok is volatile; avoid exact cadence unless dated. | +| TikTok WebSocket mode may miss about 50% of messages in some sessions. | Q&A exports, TikTok playbook | Numeric rate is historical and may vary by region/build/account. | `social_stream/sources/tiktok.js`, app TikTok manager, current tests/support reports. | Say WebSocket may be less complete than Standard in some cases. | +| TikTok fixes usually ship within 24-48 hours after platform breakage. | support instructions/playbook | Creates expectation/promise Steve may not want. | release history and maintainer policy. | Avoid promises; say update/check announcements. | +| TikTok Standard mode requires visible/focused capture page. | support instructions/playbook/Q&A | Current app/extension behavior may differ by mode and browser throttling workaround. | TikTok source and app capture window behavior. | Keep as likely operational advice; mark mode-specific. | +| TikTok gift combos should show incremental values like 3, 10, 25, 30. | support instructions/Q&A | Aggregation/dedupe may have changed or be setting-dependent. | TikTok gift event code and settings. | Mark as TikTok-side behavior pending code check. | +| WebSocket mode should be tried first for TikTok. | older Q&A/config docs | Conflicts with other support notes that Standard is more complete or needed for regional age verification. | Current TikTok app/source docs. | Present as "try both modes", not a preference. | +| YouTube auto-select live chat setting exists and is Standard-only. | top issues summary | Exact setting label/path may be old. | settings UI/code and YouTube source. | Mention only after current UI check. | +| YouTube gifts are supported in both Standard and WebSocket modes. | recent curated SQLite support record | Could be build/version-specific. | YouTube source, WSS source, event contract. | Candidate for YouTube intense pass. | +| YouTube moderation actions can replay gift notifications in standalone app. | expanded Q&A | May be fixed or specific to one API path. | YouTube app/API source and issue history. | Keep as historical issue only. | +| Google/YouTube embedded sign-in is blocked; use extension or WebSocket. | support instructions/Q&A | Generally plausible but exact fallback varies by app version and OAuth flow. | `ssapp` YouTube auth handler/source setup. | Keep as auth troubleshooting caveat. | +| Twitch WebSocket OAuth callback uses ports 8080/8181 and there is no setting to change them in v0.3.128. | recent curated SQLite support record | Version-specific; current app may have changed. | `ssapp/resources/electron-twitch-handler.js`. | Port order source-checked as `8181`, then `8080`; "no setting to change" still needs UI/source check before final claim. | +| Twitch `Activate` is required even if not live. | recent QA entry | Might be true for specific source mode only. | Twitch source/app activation code. | Include as first check after source pass. | +| Channel points require EventSub/WebSocket scopes, not IRC/basic chat. | expanded Q&A | Scope and event support can change. | Twitch provider/EventSub code. | Needs Twitch intense pass. | +| Kick CAPTCHA/human verification is Kick-side and extension is preferred. | support instructions/Q&A | Platform behavior changes; workarounds may be mode-specific. | Kick source and app WebSocket/external-browser code. | Keep as support-derived, volatile-platform. | +| Kick external-browser login can be completed by copying URL into the right browser profile. | recent support record | Exact UX depends on app implementation. | Kick app source/auth handler. | Candidate for auth docs. | +| Rumble popup URL `https://rumble.com/chat/popup/424470600` and live URL workaround `https://rumble.com/USERNAME/live`. | top issues summary | Example URL may be thread-specific; platform URL patterns may change. | Rumble source docs/code. | Do not use exact example as generic instruction. | +| Facebook Live capture must be as viewer, not publisher, and mobile data does not work. | support instructions/config Q&A | Mobile-data claim may be old or situation-specific. | Facebook source/current platform behavior. | Keep as historical until verified. | +| LinkedIn own comments may not appear because markup differs; beta extension may be needed. | top issues summary | Likely old DOM/build issue. | LinkedIn source/release history. | Historical only. | +| Mixcloud chat stops after 30-45 minutes and refresh restores it. | top issues summary | Could be single user/session/platform issue. | Mixcloud source/current reports. | Historical only. | +| Linux/AppImage Google/YouTube sign-ins failed on older builds. | top issues summary | OS/build-specific and possibly fixed. | `ssapp` Linux build notes and current issues. | Historical until source/release checked. | +| Desktop app settings are stored in localStorage/Electron app data and can be cleared by cleanup tools. | support instructions/Q&A | Cleanup-tool cause is support-derived, but storage split is real. | `ssapp/state.js`, `ssapp/main.js`, `ssapp/settings-backup.js`. | Desktop storage/backup paths are now source-backed in `settings-loss-and-backups.md`; cleanup-tool cause remains support-derived. | +| Event Flow survives while other settings wipe because it uses a different storage mechanism. | Q&A exports | Inferred support explanation. | Event Flow storage code. | Do not state as fact yet. | +| Do not uninstall the extension to update or settings are deleted. | support instructions/config Q&A and `social_stream/README.md` | Exact backup/export UI should be current. | extension storage/export code. | Safe as general warning; verify exact export/import steps. | +| `dock.html` must remain open for overlay to receive messages. | triage macro/cross-product guide | May be true in some relay modes but current overlay may connect independently to the relay. | dock/overlay relay code. | Phrase as "keep source/dock/session active" until verified. | +| Enabling four server-mode/server-relay toggles fixes OBS blank/test-message cases. | cross-product integration guide | UI names and number of toggles may be old. | settings UI, relay code, server options. | Do not publish exact "four toggles" claim until source checked. | +| Reopening generated dock/overlay links is required after settings changes. | support records | Some settings are URL params; others may sync live. | settings URL-generation and storage sync code. | Document per-setting only after source pass. | +| OBS Browser Source must include transparent CSS `rgba(0,0,0,0)`. | expanded Q&A | OBS defaults and SSN themes may already be transparent; custom CSS may be unnecessary. | current overlay CSS/themes and OBS guidance. | Treat as fallback, not mandatory. | +| System/browser TTS can be unlimited, but cloud TTS may rate-limit. | expanded Q&A | Provider details and free/paid boundaries can change. | TTS provider code/docs. | Keep high-level; verify provider specifics. | +| OBS TTS may require OBS `--autoplay-policy=no-user-gesture-required`. | expanded Q&A | OBS version/platform dependent. | OBS docs/current testing. | Use as advanced workaround only. | +| Local Kokoro/custom TTS endpoint fixed in beta. | recent support record | Version-specific. | TTS provider source/release notes. | Historical until current code checked. | +| SSN has Close to Tray/start-minimized flags. | recent support record | App-version-specific. | `ssapp/main.js`, menus/tray/CLI handling. | `Close to Tray` and `Minimize to Tray` are source-checked; start-minimized still needs source verification. | +| Hidden capture pages reopening was fixed in v0.3.127. | recent support record | Version-specific and may involve local app repo. | `ssapp` window state/source auto-activate code. | Historical/fixed-bug note only. | +| Translucent page background can break the custom right-click menu in standalone app Electron. | recent support record | Version/Electron-specific bug. | `ssapp` window/context menu handling and current Electron version. | Historical app issue until verified. | +| AI cohost DeepSeek fails when receiving `image_url`; provider does not support that field. | QA entry | Provider API support changes; exact SSN request path unknown. | AI/cohost provider code and current provider docs. | Needs AI provider pass. | +| VPZone source should be added from the source button with lowercase username. | recent support record | Source-specific and API-specific. | VPZone source code. | Candidate for later platform page. | +| `user_banned` event exists in beta for Twitch/Kick/YouTube. | recent support record | Beta/current mismatch and event contract risk. | event reference, source emitters, WebSocket API. | Do not document as current until verified. | -Use this as a holding area for contradictions, old support advice, or claims that require line-level source review. +## Verification Workflow -## Planned Sections +For each claim: -- Claim -- Source -- Risk -- Verification needed -- Final decision +1. Find the current source file or public doc that implements it. +2. Record whether the behavior is extension-only, app-only, overlay-only, API-only, or platform-mode-specific. +3. Check whether the support claim is versioned, inferred, or contradicted by another source. +4. Move verified content into the relevant topic doc. +5. Leave stale or unverified content here with a dated note. + +## Final-Doc Wording Rules + +- Prefer "try" and "check" for platform-volatile workarounds. +- Avoid exact time-to-fix promises. +- Avoid exact support percentages unless they come from measured current data. +- Do not name old version numbers in user-facing docs unless the page is explicitly historical. +- Do not copy support-bot phrasing with stale UI paths. diff --git a/docs/agents/12-development/adding-a-source.md b/docs/agents/12-development/adding-a-source.md index fdd8221b6..f41b763c0 100644 --- a/docs/agents/12-development/adding-a-source.md +++ b/docs/agents/12-development/adding-a-source.md @@ -1,30 +1,252 @@ # Adding A Source -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started from manifest/source patterns. This is a developer guide, not a full code tutorial. -## Purpose +## Source Anchors -Document how to add or modify a platform source safely. +- `sources/*.js` +- `sources/websocket/*.html` +- `sources/websocket/*.js` +- `sources/generic.js` +- `manifest.json` +- `background.js` +- `api.md` +- `docs/event-reference.html` +- `docs/js/sites.js` +- `README.md` +- `custom_sample.js` +- `sample_wss_source.html` +- `C:\Users\steve\Code\ssapp\AGENTS.md` -## Source Anchors +## Before Adding A Source + +Confirm the intended integration type: + +| Integration Type | Use When | Typical Files | +| --- | --- | --- | +| DOM content script | Chat is visible in a web page or popout | `sources/platform.js`, `manifest.json` | +| Static/manual picker | User manually selects a post/comment | `sources/static/platform.js`, manifest entry | +| Injected helper | Need page-context access to WebSocket/local variables | `sources/inject/*.js`, `web_accessible_resources`, content script | +| WebSocket/API source page | Platform has cleaner API/socket/token flow | `sources/websocket/platform.html`, `sources/websocket/platform.js`, manifest entry | +| External custom source | Third-party app can emit SSN JSON | API or `sample_wss_source.html` pattern | +| Generic proof of concept | Platform has ordinary chat DOM | Start with `sources/generic.js` ideas | + +Do not add a full source when a small user-specific custom script or API integration is enough. + +## Source File Pattern + +Most DOM sources follow this shape: + +1. Wrap code in an IIFE to avoid leaking globals. +2. Define helpers for text extraction, HTML escaping, image/avatar handling, and deduplication. +3. Request SSN settings: + +```javascript +chrome.runtime.sendMessage(chrome.runtime.id, { getSettings: true }, function(response) { + // response.state, response.streamID, response.settings +}); +``` + +4. Watch the chat container with `MutationObserver` or platform-specific events. +5. Parse each new message into an SSN payload. +6. Send the payload: + +```javascript +chrome.runtime.sendMessage(chrome.runtime.id, { message: data }, function() {}); +``` + +7. Listen for responses/commands if the source supports sending chat back to the platform. + +Common field baseline: + +```javascript +const data = {}; +data.chatname = name; +data.chatmessage = message; +data.chatimg = avatarUrl || ""; +data.chatbadges = badges || ""; +data.backgroundColor = ""; +data.textColor = ""; +data.contentimg = ""; +data.hasDonation = ""; +data.membership = ""; +data.textonly = settings.textonlymode || false; +data.type = "platformname"; +data.id = Date.now() + Math.floor(Math.random() * 1000000); +``` + +Keep `type` lowercase and stable. It controls default source icon lookup and downstream CSS selectors. + +## Manifest Changes + +Add or update a `content_scripts` entry in `manifest.json`: + +```json +{ + "js": ["./sources/platform.js"], + "matches": ["https://example.com/live/*"] +} +``` + +Also check whether the source needs: + +- `host_permissions` entries for API/fetch calls or broader URL access. +- `web_accessible_resources` if the page needs to load extension-packaged scripts, providers, SDKs, or injected helpers. +- `run_at` if the script must run before normal document idle timing. +- `all_frames` if chat is embedded in an iframe. +- Equivalent handling for store/MV3/firefox build variants if those files differ. + +Current `manifest.json` already has many source entries and broad host permissions. Copy the local pattern for similar sources rather than inventing a new structure. + +## Icons And Source Metadata + +For a new `type`, add/confirm: + +- Source icon in `sources/images/`. +- Any public supported-sites metadata in `docs/js/sites.js`. +- README support note if the setup is user-facing or unusual. +- Event reference entry if the source emits normalized events. +- Platform agent doc if it is a major source or has recurring support needs. + +If `sourceImg` is used, make sure it represents a sub-source/channel and does not duplicate the default `type` icon unnecessarily. + +## Payload Contract + +Follow the documented payload contract in `api.md` and `docs/event-reference.html`. + +Important fields: + +- `chatname`: display name. +- `chatmessage`: message body. Sanitized HTML is allowed only when `textonly` is false. +- `chatimg`: avatar URL or small data URI. +- `type`: lowercase source identifier. +- `textonly`: true means render as plain text. +- `hasDonation`: donation/gift/bits amount label. +- `membership`: member/subscription state. +- `subtitle`: short secondary membership/donation detail. +- `event`: normalized event name when this is not a normal chat message. +- `meta`: structured extra details for event/UI/integration consumers. +- `id`: stable-enough unique message ID for deletion/dedup/routing. +- `userid`: platform user ID when available. + +Do not create new top-level fields casually. Prefer `meta` for source-specific details unless existing overlays need a top-level value. + +## Event Support + +Use `docs/event-reference.html` as the source of truth for normalized event names and field meanings. + +Confirmed rules from current docs: + +- To hide events in dock/featured pages, users can use `&hideevents`, `&hideallevents`, or `&filterevents=...`. +- Donation-style messages should still populate `hasDonation` even if `event` is blank or source-specific. +- YouTube, Twitch, and Kick need WebSocket mode for many richer stream events. +- DOM capture is usually enough for chat and limited system events, but not always enough for follows, raids, subscriptions, or detailed gifts. + +When adding events: + +- Reuse existing event names when possible. +- Document source-specific gaps. +- Include sample payloads in the event reference for major platforms. +- Keep human labels short enough for overlays. + +## Sending Chat Back + +Some sources support auto-reply or API `sendChat` behavior. Before implementing outbound chat: + +- Verify the page has an input field and submit path that can be automated safely. +- Check platform restrictions and rate limits. +- Respect source settings and user toggles. +- Avoid sending duplicate replies from multiple open tabs. +- Confirm Firefox/app support if using Chromium-only APIs. + +Auto-responder/debugger behavior may be Chromium-only and can show the browser debugging bar unless Chrome is launched with `--silent-debugger-extension-api`. + +## WebSocket/API Source Pages + +Use `sources/websocket/` for source pages that connect to platform APIs or sockets. + +Typical pieces: + +- HTML page for configuration/login/user input. +- JS source that connects to platform API/socket. +- CSS when needed. +- Manifest entry that injects the helper on hosted/local source-page URLs. +- Provider/shared utility entries in `web_accessible_resources` if loaded from extension package. + +Supported local/dev URL patterns in manifest often include: + +- `https://socialstream.ninja/sources/websocket/platform*` +- `https://beta.socialstream.ninja/sources/websocket/platform*` +- `file:///.../sources/websocket/platform.html*` +- `http://localhost:8080/*/platform.html*` +- `http://localhost:8181/*/platform.html*` + +Match the existing hosted/local/beta pattern for the closest source. + +## Standalone App Compatibility + +Per `ssapp` project instructions, Social Stream source edits belong in `C:\Users\steve\Code\social_stream`. The standalone app loads Social Stream source files remotely from that repo at startup. Do not make source changes in `ssapp/resources/social_stream_fallback` during normal work; that folder is a rebuilt fallback bundle. + +When adding a source, consider: + +- Does the source need normal browser cookies/session behavior that Electron may not have? +- Does OAuth/sign-in work inside Electron, or does it need an app-side helper? +- Does the app need source URL parsing or default-source metadata updates? +- Does the source assume `chrome.*` extension APIs that need app shims? +- Does a WebSocket source page work better for app mode? + +If app behavior changes, verify in the actual app. Syntax checks are not enough for this project. + +## Testing Checklist + +Minimum source validation: + +- Load the exact matching URL in the extension. +- Confirm the extension is enabled. +- Confirm `getSettings` succeeds and respects `textonlymode`. +- Send a normal chat message and inspect dock payload. +- Confirm duplicate messages are not emitted. +- Confirm avatars, badges, membership, donation, and content images render when available. +- Confirm message deletion/moderation sync if the source supports it. +- Confirm sending chat back, if implemented. +- Confirm visibility/background behavior. +- Confirm hosted/local/beta WebSocket source URL patterns if relevant. +- Confirm standalone app behavior if the source is expected to work there. + +Docs/support updates: + +- Update README if setup steps matter to users. +- Update `docs/js/sites.js` if the public site list should include it. +- Update `docs/event-reference.html` if it emits standardized events. +- Update agent docs when the source is likely to become a support topic. + +## Code Review Risks + +Look specifically for: -- `social_stream/sources/README.md` -- `social_stream/sources/*.js` -- `social_stream/manifest.json` -- `social_stream/background.js` -- `social_stream/docs/event-reference.html` -- `ssapp/tests/electron/source-url-parsing-regression.js` +- DOM selectors that are too broad and capture duplicates. +- Message HTML inserted without escaping when `textonly` is true. +- Huge data URIs or avatars/content images. +- Missing `type` or inconsistent source type names. +- Unbounded Maps/Sets/timeouts. +- MutationObservers attached to `document.body` without filtering. +- Reconnect loops with no backoff. +- Chat send automation that can spam or duplicate replies. +- Tokens/API keys logged to console or embedded in committed files. +- Platform-specific assumptions that break extension/app parity. -## Starter Notes +## Useful References -Source scripts may run in both the extension and the app. They need compatibility with old-school browser scripts and should preserve event payload contracts. +- `sources/generic.js`: broad DOM-capture reference. +- `sources/bandlab.js`, `sources/bigo.js`, `sources/chatroll.js`: straightforward DOM-source patterns. +- `sources/websocket/youtube.js`, `sources/websocket/twitch.js`, `sources/websocket/kick.js`: richer source-page patterns. +- `sample_wss_source.html`: minimal external-source API pattern. +- `custom_actions.js`: message-processing customization template. +- `api.md`: payload and API command reference. -## Planned Sections +## Follow-Up Extraction Needs -- Source file pattern -- Manifest changes -- Icons and settings -- WebSocket source pattern -- Payload fields -- App compatibility -- Tests and docs updates +- Create a per-source implementation matrix from `manifest.json`. +- Add exact app-side source URL parsing notes from `ssapp` tests/code. +- Build a source template with placeholders and required manifest/docs changes. +- Add examples for injected-helper sources such as StreamElements/Whatnot/VPZone. diff --git a/docs/agents/12-development/build-and-release-boundaries.md b/docs/agents/12-development/build-and-release-boundaries.md index 4f6d7a4a5..117961961 100644 --- a/docs/agents/12-development/build-and-release-boundaries.md +++ b/docs/agents/12-development/build-and-release-boundaries.md @@ -1,28 +1,171 @@ # Build And Release Boundaries -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started on 2026-06-24. ## Purpose -Document build, packaging, release, and repo-boundary rules relevant to SSN docs. +Document build, packaging, release, and repo-boundary rules that matter when answering SSN/SSApp development or release questions. ## Source Anchors +- `ssapp/AGENTS.md` - `ssapp/RELEASE.md` - `ssapp/package.json` - `ssapp/scripts/*` -- `social_stream/README.md` -- `social_stream/docs/download.html` +- `ssapp/resources/README.md` +- `social_stream/AGENTS.md` +- `social_stream/package.json` -## Starter Notes +## Critical Release Boundary -App release tags and artifacts belong in `steveseguin/social_stream`, not in `ssapp`. This page should be source-checked before any release/deploy work. +Desktop app binaries are built from `ssapp`, but app release tags and artifacts belong in: -## Planned Sections +```text +steveseguin/social_stream +``` -- Extension release surfaces -- Standalone app builds -- Fallback bundle warning -- Release note style -- Artifact upload boundaries -- Do-not-do list +Do not create app release tags or GitHub releases in: + +```text +steveseguin/ssn_app +``` + +The app release guide says to create GitHub releases as pre-releases; Steve promotes them when ready. + +If Steve says "ship a release", confirm target and scope before creating tags, releases, or uploading artifacts. + +## ssapp Build Commands + +From `ssapp/package.json` and app instructions: + +- `npm run start`: start Electron app. +- `npm run start2`: start development mode with `--running-from-source`. +- `npm run start3`: start from `C:/Users/steve/Code/social_stream/`. +- `npm run start4`: macOS source path variant. +- `npm run update:fallback`: regenerate Social Stream fallback bundle. +- `npm run clean`: remove `dist`. +- `npm run build:win32`: Windows NSIS + portable. +- `npm run build:darwin`: macOS x64 + arm64. +- `npm run build:linux`: Linux AppImage. +- `npm run build:rpi`: Raspberry Pi Linux deb path. +- `npm run release`: electron-builder publish flow. +- `npm run submit:virustotal`: submit Windows exe files to VirusTotal. + +Prebuild scripts run submodule checks and fallback update. This does not make the fallback folder a normal edit target. + +## Expected Windows Artifacts + +The release guide expects Windows artifacts under `ssapp/dist/`, including: + +- `socialstreamninja-setup-.exe` +- `socialstreamninja-portable.exe` +- `socialstreamninja_win_v_installer.zip` +- `socialstreamninja_win_v_portable.zip` + +Artifact names are controlled in `ssapp/package.json` electron-builder config. + +## Platform Build Order + +The release guide's current order: + +1. Build Windows in `ssapp`. +2. Submit Windows installer and portable exe to VirusTotal. +3. Upload Windows artifacts to the `steveseguin/social_stream` GitHub release. +4. Build Linux AppImage via WSL2 after Windows build is finished. +5. Upload Linux AppImage to the same `steveseguin/social_stream` GitHub release. +6. Steve handles macOS builds for now. + +## VirusTotal Rules + +VirusTotal key: + +- local `.secret` at repo root with `VT_API_KEY=...` +- or `VT_API_KEY` environment variable + +Only submit the two Windows exe files: + +- `dist/socialstreamninja-setup-.exe` +- `dist/socialstreamninja-portable.exe` + +Do not submit Linux AppImage builds to VirusTotal. + +`.secret` must stay gitignored and must not be committed. + +## Fallback Bundle Rule + +`ssapp/resources/social_stream_fallback` is generated. + +Rules: + +- Do not modify it manually. +- Do not treat it as source. +- Do not use it for normal code reading or docs extraction. +- It is rebuilt by `npm run update:fallback` and prebuild scripts. + +Source changes belong in: + +```text +C:\Users\steve\Code\social_stream +``` + +## Release Notes Style + +GitHub release notes for app releases should follow the Social Stream style. + +Required start: + +```md +:point_right::point_right: EXPORT AND SAVE YOUR SETTINGS BEFORE UPDATING :warning::warning: +``` + +Required heading: + +```md +### What's new in this version: +``` + +Rules: + +- Write for normal users, not developers. +- Include every important user-facing change included since the prior release package, not only the final version bump. +- Check recent `steveseguin/social_stream` releases before writing notes. +- Do not include redundant platform intro text such as "Windows, macOS, and Linux pre-release"; the Downloads table already shows platforms. +- Include the screenshot image specified in `ssapp/RELEASE.md` when preparing actual release notes. +- Include a downloads table with uploaded files. + +## Git Push Contract + +The `social_stream/AGENTS.md` push contract says: + +- When Steve says `push`, push to `beta`. +- Push all current changes unless Steve explicitly excludes something. +- Use this serial order only: + 1. `git add -A` + 2. `git commit` (use `--allow-empty` if needed) + 3. `git pull --rebase origin beta` + 4. `git push origin beta` +- Do not parallelize that git flow. +- Do not add extra git inspection commands unless Steve asks. + +Global/current instructions also say never create a branch unless Steve explicitly asks. + +## Do Not + +- Do not create git tags in `ssapp` for app releases. +- Do not create or upload GitHub releases against `steveseguin/ssn_app`. +- Do not assume `ssapp/package.json` publish config means `ssn_app` is the public release target. +- Do not touch generated fallback files manually. +- Do not commit secrets, certs, `.env`, `.secret`, or signing material. +- Do not call release validation "tested" unless the appropriate real workflow was run. + +## If Something Goes Wrong + +If a wrong `ssapp` tag or release is created, stop and report it to Steve before cleanup. + +Do not delete tags/releases without explicit approval. + +## Remaining Extraction Targets + +- Inspect current GitHub workflow files for exact release artifact automation. +- Cross-check public download docs once release/upload docs are needed. +- Add a step-by-step release runbook only when Steve asks for release work. diff --git a/docs/agents/12-development/index.md b/docs/agents/12-development/index.md new file mode 100644 index 000000000..751d437a7 --- /dev/null +++ b/docs/agents/12-development/index.md @@ -0,0 +1,33 @@ +# Development Index + +Status: heavy passes started for development repo map, shared-code rules, provider/shared utilities, testing, and release boundaries. + +## Purpose + +This section covers how agents should reason about SSN development work across the Chrome extension/web repo and the standalone Electron app. + +## Pages + +- `adding-a-source.md`: heavy extraction pass started. +- `repo-map.md`: heavy extraction pass started. +- `shared-code-rules.md`: heavy extraction pass started. +- `provider-cores-and-shared-utils.md`: provider-core files, shared utilities, web-accessible resources, and adapter boundaries. +- `testing-and-validation.md`: heavy extraction pass started. +- `build-and-release-boundaries.md`: heavy extraction pass started. + +## Most Important Rules + +- `social_stream` is the source of truth for Social Stream source behavior. +- `ssapp` is the Electron desktop wrapper and app-specific runtime/build repo. +- Do not treat `ssapp/resources/social_stream_fallback` as source. +- Keep shared browser-facing code Chrome 80 friendly unless Steve explicitly changes the baseline. +- Provider cores should stay environment-agnostic. +- Use focused tests/sanity checks honestly; app changes require real in-app/e2e validation before calling them tested. +- App release artifacts belong in `steveseguin/social_stream`, not `steveseguin/ssn_app`. + +## Suggested Next Pass + +- Build a file-by-file source map for all platform sources and top-level pages. +- Expand the manifest content-script/source-load matrix into a full 155-row public-site mapping. +- Inspect GitHub workflows for release automation and artifact handling. +- Create manual validation recipes for frequent support workflows. diff --git a/docs/agents/12-development/provider-cores-and-shared-utils.md b/docs/agents/12-development/provider-cores-and-shared-utils.md new file mode 100644 index 000000000..3a1a73336 --- /dev/null +++ b/docs/agents/12-development/provider-cores-and-shared-utils.md @@ -0,0 +1,130 @@ +# Provider Cores And Shared Utilities + +Status: heavy development pass started from `providers/*`, `shared/*`, and manifest web-accessible resources. + +## Purpose + +Use this page when changing newer provider modules, shared utilities, or source scripts that dynamically load reusable code. It explains which files are reusable cores, which are browser-facing helpers, and which manifest/resource rules matter. + +## Source Anchors + +- `providers/kick/core.js` +- `providers/twitch/chatClient.js` +- `providers/youtube/liveChat.js` +- `providers/youtube/contextResolver.js` +- `providers/youtube/proto/stream_list.proto` +- `shared/utils/scriptLoader.js` +- `shared/utils/html.js` +- `shared/utils/twitchEmotes.js` +- `shared/aiPrompt/overlayStore.js` +- `shared/ai/browserModelCatalog.js` +- `shared/ai/kokoroAssetCatalog.js` +- `shared/ai/localBrowserLLM.js` +- `shared/vendor/socket.io.min.js` +- `shared/vendor/tmi.js` +- `shared/vendor/tmi.module.js` +- `manifest.json` +- `docs/agents/12-development/shared-code-rules.md` + +## Current Provider Files + +| File | Role | Export/Interface Summary | Notes | +| --- | --- | --- | --- | +| `providers/kick/core.js` | Kick normalization helpers | Channel/token normalization, badge/image normalization, event-name mapping, profile-cache helpers, profile-detail merge helpers | Pure helper module. Keep it free of DOM, Chrome, and Electron assumptions. | +| `providers/twitch/chatClient.js` | Twitch IRC/tmi chat client core | `normalizeTwitchChannel`, `createTwitchChatClient`, `createTmiClientFactory`, `TWITCH_CHAT_EVENTS`, `TWITCH_CHAT_STATUS` | Requires an adapter/factory to provide tmi.js. Handles reconnect, normalized chat/membership/raid/notice events, and `sendMessage`. | +| `providers/youtube/liveChat.js` | YouTube live chat streaming client | `createYouTubeLiveChat`, `YOUTUBE_LIVE_CHAT_EVENTS`, `YOUTUBE_LIVE_CHAT_STATUS` | Stream mode is implemented around YouTube liveChat `messages:stream`. Poll mode currently throws a not-implemented error. Requires token, live chat ID, fetch, and AbortController support. | +| `providers/youtube/contextResolver.js` | YouTube channel/video/live-chat resolver | `createYouTubeLiveChatContextResolver`, `resolveYouTubeLiveChatContext` | Uses YouTube Data API, requires OAuth token, resolves direct chat ID, video ID, or channel to live chat context. | +| `providers/youtube/proto/stream_list.proto` | YouTube stream protobuf reference | Data schema/reference file | Treat as provider protocol support material, not a runtime browser helper by itself. | + +## Current Shared Files + +| File | Role | Notes | +| --- | --- | --- | +| `shared/utils/scriptLoader.js` | Script loading helper | Exports script load helpers. Browser-facing and listed as web-accessible. | +| `shared/utils/html.js` | HTML/text escaping helper | Exports safe HTML/text conversion helpers. | +| `shared/utils/twitchEmotes.js` | Twitch native emote parsing/rendering | Exports parse/stringify/render helpers for Twitch emote ranges. | +| `shared/aiPrompt/overlayStore.js` | AI prompt overlay package/local state helper | UMD-style wrapper usable in browser/global and CommonJS-like contexts. | +| `shared/ai/browserModelCatalog.js` | Local browser model metadata/helper | UMD-style wrapper. Used for browser-local model choices. | +| `shared/ai/kokoroAssetCatalog.js` | Kokoro TTS asset URL/path helper | UMD-style wrapper. Not currently listed in manifest web-accessible resources from the inspected group. | +| `shared/ai/localBrowserLLM.js` | Worker-backed local browser LLM client | UMD-style wrapper. Manages worker lifecycle, generation, status/progress callbacks, and cleanup. | +| `shared/vendor/socket.io.min.js` | Vendored Socket.IO client | Loaded locally; current manifest content-script entry is for Velora WebSocket source pages. | +| `shared/vendor/tmi.js` | Vendored tmi.js | Local Twitch IRC client dependency. | +| `shared/vendor/tmi.module.js` | Vendored tmi.js module build | Local module variant for Twitch provider/source use. | + +## Manifest Web-Accessible Resources + +The current manifest has two `web_accessible_resources` groups. The broad group exposes 15 resources to ``, including: + +- `providers/kick/core.js` +- `providers/twitch/chatClient.js` +- `providers/youtube/liveChat.js` +- `providers/youtube/contextResolver.js` +- `shared/utils/scriptLoader.js` +- `shared/utils/html.js` +- `shared/utils/twitchEmotes.js` +- `shared/aiPrompt/overlayStore.js` +- `shared/vendor/socket.io.min.js` +- `shared/vendor/tmi.js` +- `shared/vendor/tmi.module.js` +- `shared/ai/browserModelCatalog.js` +- `shared/ai/localBrowserLLM.js` + +Support/development note: if a content script dynamically imports or loads a provider/shared helper through the extension runtime, the file must be reachable through `web_accessible_resources`. Forgetting this can make a feature work on hosted/local pages but fail inside the packaged extension. + +## Provider-Core Rules + +Provider cores should remain environment-agnostic. + +Do: + +- Pass `fetch`, token providers, loggers, client factories, and clock/sanitize/avatar helpers as options where needed. +- Return plain data structures and normalized events. +- Keep reconnect/status/event emitters local to the provider interface. +- Keep secrets redacted in logs. +- Keep module APIs small and testable. + +Avoid: + +- Direct `chrome.*` calls. +- Direct Electron IPC calls. +- Direct DOM reads from a third-party platform page. +- Direct overlay/dock mutations. +- Remote executable imports. +- Hard-coded app-only or extension-only globals. + +## Adapter Boundary + +The expected split is: + +- Provider core: normalize, connect, retry, parse provider events, and expose an interface. +- Source script or app handler: obtain credentials, load dependencies, talk to Chrome/Electron/runtime APIs, and forward normalized payloads into SSN. +- Overlay/dock/API layer: render, filter, route, and control messages after they are already normalized. + +If a provider core needs a platform-specific API request, pass in `fetchImplementation` or an adapter option rather than binding to a specific runtime. + +## Compatibility Notes + +- Many existing browser-facing scripts still need Chrome 80-friendly syntax. +- Some provider/shared files use ESM exports and are loaded as modules from compatible contexts. +- Do not convert old content scripts or overlay pages to module syntax without checking Chrome extension, hosted, Lite, and Electron app consumers. +- Use local vendored dependencies from `shared/vendor`, `thirdparty`, or similar approved local paths. Do not add CDN executable scripts to extension code. + +## Support Answer Rules + +When a user asks about provider-backed behavior: + +1. Identify whether they are using DOM capture, WebSocket source page, or standalone app provider/OAuth behavior. +2. Check whether a provider core is involved or whether the platform still uses a classic source script only. +3. Check whether auth/token/API setup is required. +4. Check whether the provider has implemented the requested mode. Example: current YouTube live chat provider stream mode exists, but poll mode throws not implemented in the inspected core. +5. Do not promise event coverage or send-chat support from the provider file alone; check the adapter/source handler that forwards data into SSN. + +## Extraction Gaps + +Needed intense passes: + +- Trace exact dynamic import/load paths from source scripts into each provider/shared helper. +- Map provider-core normalized events to final SSN event payloads. +- Verify app-vs-extension loading paths for provider modules. +- Add unit or sanity test references for provider helpers where tests exist. +- Decide whether `shared/ai/kokoroAssetCatalog.js` should be added to web-accessible resources if extension contexts need it. diff --git a/docs/agents/12-development/repo-map.md b/docs/agents/12-development/repo-map.md index e698b8758..b92863f7f 100644 --- a/docs/agents/12-development/repo-map.md +++ b/docs/agents/12-development/repo-map.md @@ -1,29 +1,157 @@ # Development Repo Map -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started on 2026-06-24. ## Purpose -Document where code lives and which repo/file should be changed for SSN development work. +This page tells agents where SSN code lives and which repository should be changed for common work. ## Source Anchors - `social_stream/AGENTS.md` - `ssapp/AGENTS.md` - `social_stream/manifest.json` +- `social_stream/package.json` - `ssapp/package.json` +- `ssapp/RELEASE.md` - `ssapp/resources/README.md` -## Starter Notes +## Repository Roles -`social_stream` is the source of truth for Social Stream source files. `ssapp` loads those files and should not treat its fallback bundle as primary source. +`C:\Users\steve\Code\social_stream` -## Planned Sections +- Primary Social Stream Ninja source of truth. +- Chrome extension source. +- Hosted web pages and overlays. +- Platform content scripts under `sources/`. +- WebSocket/bridge source pages under `sources/websocket/`. +- Shared cross-surface utilities under `shared/`. +- Provider cores under `providers/`. +- Public docs under `docs/` plus root docs such as `README.md`, `api.md`, and `parameters.md`. +- The only place this documentation project writes: `docs/agents/`. -- Repo roles -- Extension files -- App files -- Shared files -- Public docs -- Tests -- Files to avoid +`C:\Users\steve\Code\ssapp` + +- Electron standalone app wrapper. +- App-specific main/preload/renderer/state code. +- App-specific platform handlers and IPC/security code. +- Build/package/release artifact generation for the desktop app. +- Loads Social Stream source from `C:\Users\steve\Code\social_stream` during development. + +## Source Of Truth Rule + +For Social Stream source behavior, edit `social_stream`. + +Do not treat: + +```text +ssapp/resources/social_stream_fallback +``` + +as primary source. The app instructions and `ssapp/resources/README.md` both say it is a generated bundle mirror for packaged/distributed builds and is rebuilt on build/update. + +Normal app work should not read, browse, edit, or spend time in that fallback folder. + +## social_stream Layout + +High-value directories: + +- `sources/`: platform DOM/content scripts loaded by the extension and often used by the app. +- `sources/websocket/`: bridge/source pages that can run in extension and Electron contexts. +- `providers/`: platform provider cores, intended to stay environment-agnostic. +- `shared/`: cross-surface utilities and shared AI/provider/browser helpers. +- `settings/`: settings UI/config pieces. +- `actions/`: Event Flow editor/system/guides/examples. +- `themes/`: overlay theme examples. +- `games/`: individual game pages. +- `docs/`: public docs and event reference. +- `docs/agents/`: AI-focused documentation set created by this project. +- `scripts/`: Playwright checks, model/AI checks, asset sync helpers. +- `tests/`: Node/browser regression tests and fixtures. +- `lite/`: standalone web app surfaces deployed independently. +- `thirdparty/`, `shared/vendor/`, `lite/vendor/`: local vendored dependencies. + +Important root files: + +- `manifest.json`: MV3 extension manifest, content scripts, permissions, web-accessible resources. +- `service_worker.js`: extension service worker bootstrap. +- `background.js` / `background.html`: extension runtime and message routing. +- `popup.html` / `popup.js`: extension settings/control UI. +- `dock.html`, `featured.html`, `multi-alerts.html`, `actions.html`, etc.: overlay/tool pages. +- `api.md`, `parameters.md`, `docs/event-reference.html`: public API/parameter/payload references. + +## ssapp Layout + +Important app files: + +- `main.js`: Electron main process. +- `preload.js`: bridge exposed to renderer/source pages. +- `renderer.js`: app renderer UI behavior. +- `state.js`: app state persistence. +- `index.html`, `main.css`: app shell. +- `resources/electron-*-handler.js`: OAuth/platform handlers. +- `resources/kick-ws-client.js`: Kick WebSocket client. +- `tiktok/`: TikTok connection management. +- `tiktok-signing/`: TikTok signing helper. +- `tests/electron/`: app diagnostics/regression scripts. +- `tests/tiktok/`: TikTok mode/regression scripts. +- `scripts/updateSocialStreamFallback.js`: generated fallback bundle updater. +- `scripts/submit-virustotal.js`: release submission helper. + +Avoid normal edits in: + +- `resources/social_stream_fallback/` +- generated build outputs such as `dist/` +- secrets/certs/env files unless the task explicitly requires release/signing work and Steve has approved it + +## Extension Manifest Notes + +`manifest.json` is MV3: + +- `manifest_version: 3` +- background service worker: `service_worker.js` +- CSP allows extension pages to load self scripts and `wasm-unsafe-eval`, but not arbitrary remote executable scripts +- many host permissions and content-script matches +- `web_accessible_resources` exposes shared/provider modules such as provider cores and `shared/utils/*` + +When adding a shared script used by content scripts or extension pages, update the manifest if extension access requires it. + +## What To Change Where + +Platform capture bug: + +- Start in `social_stream/sources/.js` or `sources/websocket/.*`. +- If app-only auth/IPC is involved, also inspect `ssapp/resources/electron-*-handler.js` or `ssapp/preload.js`. + +Overlay behavior: + +- Start in the specific root overlay/tool page: `dock.html`, `featured.html`, `multi-alerts.*`, `waitlist.html`, `poll.html`, `timer.html`, etc. +- Shared payload contract changes need `docs/event-reference.html`. + +Event Flow: + +- `actions/EventFlowEditor.js` +- `actions/EventFlowSystem.js` +- `actions/*.html` guides +- `tests/eventflow-*.test.js` + +Standalone app source-window or state behavior: + +- `ssapp/main.js` +- `ssapp/preload.js` +- `ssapp/state.js` +- `ssapp/renderer.js` +- app tests under `ssapp/tests/electron/` + +Release/build: + +- `ssapp/package.json` +- `ssapp/RELEASE.md` +- `ssapp/scripts/*` +- public release artifacts in `steveseguin/social_stream` releases, not `ssn_app` releases + +## Remaining Extraction Targets + +- Build a file-by-file source map for all top-level pages in `social_stream`. +- Add a provider-core map for `providers/*`. +- Add a source-script load map by parsing `manifest.json` content scripts. diff --git a/docs/agents/12-development/shared-code-rules.md b/docs/agents/12-development/shared-code-rules.md index 222ebeb31..dade17fb2 100644 --- a/docs/agents/12-development/shared-code-rules.md +++ b/docs/agents/12-development/shared-code-rules.md @@ -1,28 +1,199 @@ # Shared Code Rules -Status: framework only. Detailed extraction not started. +Status: heavy extraction pass started on 2026-06-24. ## Purpose -Document rules for code shared between extension, app, hosted pages, and standalone web surfaces. +Document rules for code shared between the Chrome extension, Electron app, hosted pages, Lite pages, overlays, provider cores, and bridge/source pages. ## Source Anchors - `social_stream/AGENTS.md` +- `social_stream/manifest.json` - `social_stream/shared/**` - `social_stream/providers/**` - `social_stream/sources/websocket/**` - `ssapp/preload.js` -## Starter Notes +## Compatibility Baseline -Repo instructions say shared source scripts must work in both Chrome extension and Electron app contexts. Provider cores should remain environment agnostic. +Browser-facing SSN code should stay old-school and Chrome 80 friendly unless Steve explicitly raises the baseline. -## Planned Sections +Avoid by default: -- Chrome 80 compatibility -- No remote executable code in extension package -- Dynamic import patterns -- Provider core boundaries -- Shared utility placement -- Manifest/web-accessible resources +- ` - - - - Social Stream Ninja | Live Social Messaging for Content Creators - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
- - - - - - -
- - - -
-
-
-
- -
-
-
-

Consolidate Your Live Social Messaging Streams

-

Connect with your audience across Facebook, Youtube, Twitch, Zoom, and dozens more platforms - all in one place.

- -
-
- Social Stream Ninja Dashboard -
-
-
- - - \ No newline at end of file + + + + + + Social Stream Ninja Docs + + + + + + +
+ + +
+
+ +
Loading...
+
+ + Raw +
+
+
Loading documentation...
+
+
+ + + + diff --git a/featured.html b/featured.html index 1e130551e..63dd88621 100644 --- a/featured.html +++ b/featured.html @@ -2481,7 +2481,7 @@ iframe.style.left = "-100px"; iframe.style.top = "-100px"; iframe.id = "frame1"; - iframe.allow = "midi;geolocation;microphone;"; // microphone is needed for Safari webRTC P2P connections + iframe.allow = "midi;microphone;"; // microphone is needed for Safari webRTC P2P connections document.body.appendChild(iframe); var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent"; diff --git a/games/phraseguess.html b/games/phraseguess.html index 3baa6a0f0..a743aff26 100644 --- a/games/phraseguess.html +++ b/games/phraseguess.html @@ -370,7 +370,7 @@

Recent Activity

iframe.style.left = "-100px"; iframe.style.top = "-100px"; iframe.style.border = "0"; - iframe.allow = "autoplay;camera;microphone;fullscreen;picture-in-picture;display-capture;midi;geolocation;gyroscope;"; + iframe.allow = "autoplay;camera;microphone;fullscreen;picture-in-picture;display-capture;midi;gyroscope;"; document.body.appendChild(iframe); window.addEventListener("message", function(e) { diff --git a/giveaway-obs-entries.html b/giveaway-obs-entries.html index 1065eece4..4e4c8d513 100644 --- a/giveaway-obs-entries.html +++ b/giveaway-obs-entries.html @@ -900,7 +900,7 @@ iframe.style.left = "-100px"; iframe.style.top = "-100px"; iframe.id = "obs-frame"; - iframe.allow = "midi;geolocation;microphone;"; + iframe.allow = "midi;microphone;"; iframe.src = "https://vdo.socialstream.ninja/?ln&salt=vdo.ninja&password=" + password + "&push&label=dock&vd=0&ad=0&novideo&noaudio&autostart&cleanoutput&room=" + roomID; document.body.appendChild(iframe); diff --git a/giveaway.html b/giveaway.html index 57635640e..fab250593 100644 --- a/giveaway.html +++ b/giveaway.html @@ -1478,7 +1478,7 @@

🏆 Recent Winners

iframe.style.left = "-100px"; iframe.style.top = "-100px"; iframe.id = "frame1"; - iframe.allow = "midi;geolocation;microphone;"; + iframe.allow = "midi;microphone;"; iframe.src = "https://vdo.socialstream.ninja/?ln&salt=vdo.ninja&password=" + password + "&push&label=dock&vd=0&ad=0&novideo&noaudio&autostart&cleanoutput&room=" + roomID; document.body.appendChild(iframe); diff --git a/input.html b/input.html index da329ec6b..ed9cc056c 100644 --- a/input.html +++ b/input.html @@ -134,7 +134,7 @@ iframe.style.left = "-100px"; iframe.style.top = "-100px"; iframe.id = `frame_${room}`; - iframe.allow = "midi;geolocation;microphone;"; + iframe.allow = "midi;microphone;"; iframes.push(iframe); document.body.appendChild(iframe); diff --git a/samplefeatured.html b/samplefeatured.html index 6573da661..b6786046a 100644 --- a/samplefeatured.html +++ b/samplefeatured.html @@ -279,7 +279,7 @@ const iframe = document.createElement('iframe'); iframe.src = `https://vdo.socialstream.ninja/?ln&password=${this.state.password}¬mobile&salt=vdo.ninja&label=overlay&exclude=${this.state.roomID}&scene&novideo&noaudio&cleanoutput&room=${this.state.roomID}`; iframe.id = 'frame1'; - iframe.allow = 'midi;geolocation;microphone;'; + iframe.allow = 'midi;microphone;'; document.body.appendChild(iframe); window.addEventListener('message', (e) => { @@ -608,4 +608,4 @@ document.addEventListener('DOMContentLoaded', () => App.init()); - \ No newline at end of file + diff --git a/sources/websocket/twitch.js b/sources/websocket/twitch.js index 658eac689..3910fb3b8 100644 --- a/sources/websocket/twitch.js +++ b/sources/websocket/twitch.js @@ -1988,7 +1988,7 @@ async function ensureChatClientInstance() { textOnly: textOnlyMode, escapeHtml, imageClassName: 'regular-emote', - textIsSafe: true + textIsSafe: false }); } catch (error) { console.warn('Falling back to legacy Twitch emote renderer', error); diff --git a/themes/featured-styles/featured-modern.html b/themes/featured-styles/featured-modern.html index 00a87a1c4..275b5155e 100644 --- a/themes/featured-styles/featured-modern.html +++ b/themes/featured-styles/featured-modern.html @@ -501,7 +501,7 @@ iframe.style.left = "-100px"; iframe.style.top = "-100px"; iframe.id = "frame1"; - iframe.allow = "midi;geolocation;microphone;"; // microphone is needed for Safari webRTC P2P connections + iframe.allow = "midi;microphone;"; // microphone is needed for Safari webRTC P2P connections document.body.appendChild(iframe); var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent"; From d9aab1677500dbf4a84f5567ff86eafd792e13cc Mon Sep 17 00:00:00 2001 From: steveseguin Date: Wed, 24 Jun 2026 07:47:00 -0400 Subject: [PATCH 20/30] docs(agents): update navigation audit wildcard count and reference list Increase wildcardAgentRefCount from 41 to 49 to reflect new wildcard references added in recent agent documentation updates (e.g., AI agent framework and extraction progress). Also add `docs/agents/*/SITEMAP.md` to the known wildcard patterns, confirming it as an intentional cross-reference rather than a broken link. [auto-enhanced] --- docs/agents/19-navigation-and-link-audit.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/agents/19-navigation-and-link-audit.md b/docs/agents/19-navigation-and-link-audit.md index 0a8561303..7b26101ac 100644 --- a/docs/agents/19-navigation-and-link-audit.md +++ b/docs/agents/19-navigation-and-link-audit.md @@ -34,7 +34,7 @@ totalMarkdown: 161 orphanishCount: 0 localBrokenCount: 0 ambiguousBareSectionIndexCount: 0 -wildcardAgentRefCount: 41 +wildcardAgentRefCount: 49 ``` Interpretation: @@ -82,6 +82,7 @@ The audit reports wildcard references separately. Current wildcard references in - `docs/agents/11-support-kb/*.md` - `docs/agents/12-development/*.md` - `docs/agents/13-reference/*.md` +- `docs/agents/*/SITEMAP.md` - Support-refresh globs such as `qa-export-*.json` and `social-stream-*.md`. These should not be treated as broken file references unless a future rule requires replacing all wildcard section shorthand with concrete section indexes. From dee0b86c2c4235ca414ba8eb3c684c92a68178cc Mon Sep 17 00:00:00 2001 From: steveseguin Date: Wed, 24 Jun 2026 07:58:31 -0400 Subject: [PATCH 21/30] docs(agents): add priority platform answer matrix Create a priority answer matrix offering safe support phrasing and first-check routing for major live-stream platforms (YouTube, TikTok, Twitch, Kick, Rumble, Facebook, Instagram, and Discord). Update the extraction checklist (`01-extraction-checklist.md`) and resource processing ledger (`02-resource-processing-ledger.md`) to register the new heavy pass and track its corresponding output document (`08-platform-sources/priority-platform-answer-matrix.md`). [auto-enhanced] --- docs/agents/01-extraction-checklist.md | 1 + docs/agents/02-resource-processing-ledger.md | 6 +- docs/agents/08-platform-sources/SITEMAP.md | 1 + docs/agents/08-platform-sources/index.md | 3 + .../platform-capability-matrix.md | 3 + .../priority-platform-answer-matrix.md | 262 ++++++++++++++++++ .../common-question-coverage-map.md | 4 +- .../common-question-fast-path.md | 4 +- .../11-support-kb/question-intent-router.md | 5 +- .../14-validation-and-refresh-roadmap.md | 2 +- ...-objective-coverage-and-readiness-audit.md | 6 +- docs/agents/19-navigation-and-link-audit.md | 2 +- docs/agents/99-agent-index.md | 6 +- docs/agents/AGENT.md | 1 + 14 files changed, 289 insertions(+), 17 deletions(-) create mode 100644 docs/agents/08-platform-sources/priority-platform-answer-matrix.md diff --git a/docs/agents/01-extraction-checklist.md b/docs/agents/01-extraction-checklist.md index a44377af3..59d9e3e33 100644 --- a/docs/agents/01-extraction-checklist.md +++ b/docs/agents/01-extraction-checklist.md @@ -167,6 +167,7 @@ Add one entry per extraction pass. | 2026-06-24 | Codex | Common question test set | Heavy support-routing benchmark pass | `11-support-kb/common-question-test-set.md`, support/index/sitemap/ledger/audit updates | heavy-complete | Added benchmark-style test prompts for product/cost/support, install/modes, source capture, platform behavior, commands/API, URL/settings/sessions, overlays/pages, AI/TTS/RAG, customization/plugins/development, privacy, and testing claims. Each row records expected first doc, secondary proof docs, required caveat, and fail condition. This validates answer routing only, not product runtime behavior. | | 2026-06-24 | Codex | Support history refresh playbook | Heavy support-refresh workflow pass | `11-support-kb/support-history-refresh-playbook.md`, support indexes/ledger/audit updates | heavy-complete | Added a safe repeatable support-history refresh workflow with aggregate SQLite query pack, current seed counts from `knowledge.sqlite` and `stevesbot.sqlite`, latest QA export reference, raw archive gate, stale-claim decision tree, and required downstream doc updates. Counts are priority signals only, not runtime/product proof. | | 2026-06-24 | Codex | App, extension, and mode crosswalk | Heavy support-routing/reference pass | `13-reference/app-extension-mode-crosswalk.md`, support/reference indexes/checklist/ledger/audit updates | heavy-complete | Added first-stop routing for Chrome extension vs standalone app vs hosted pages, local pages, Lite, Firefox, WebSocket/API source pages, and custom sources. Includes safe answer rules, surface matrix, app-vs-extension decision matrix, common confusion points, troubleshooting routes, recommended answer shapes, and overclaim guardrails. Not runtime-tested. | +| 2026-06-24 | Codex | Priority platform answer matrix | Heavy support-routing/platform pass | `08-platform-sources/priority-platform-answer-matrix.md`, platform/support indexes/checklist/ledger/audit updates | heavy-complete | Added safe support phrasing and first-check routing for YouTube, TikTok, Twitch, Kick, Rumble, Facebook, Instagram, and Discord. The pass source-grepped send-back, source-control, auth/token, and rich-event terms, but did not perform live platform, app, or OBS testing. | | 2026-06-24 | Codex | Scoreboard controlled browser validation | Runtime browser validation | `17-runtime-validation-evidence-log.md`, `07-overlays-and-pages/live-display-utilities.md`, `07-overlays-and-pages/page-capability-matrix.md`, checklist/ledger/audit/index updates | browser-validated-partial | Ran `node scripts/playwright-scoreboard-e2e.cjs`; result `PASS scoreboard e2e`. Validated local headless Chromium behavior for `scoreboard.html` preview-mode points snapshot rendering, `maxusers`, `minpoints`, layout/theme/title/subtitle, local `chatpoints`, `donationpoints`, `customtriggers`, compact layout, and `hidepoints`. Did not test OBS, hosted page, extension/app bridge, live source payloads, WebSocket/server modes, session/password/label routing, or persistence. | | 2026-06-24 | Codex | Reactions overlay controlled browser validation | Runtime browser validation | `17-runtime-validation-evidence-log.md`, `07-overlays-and-pages/live-display-utilities.md`, `07-overlays-and-pages/page-capability-matrix.md`, checklist/ledger/audit/index updates | browser-validated-partial | Ran `node scripts/playwright-reactions-overlay-e2e.cjs`; result `Reactions overlay test passed with 12 blocked external request(s).` Validated controlled local headless Chromium behavior for popup-generated reactions URL parameters, `reactions.html` option parsing, synthetic VDO bridge liked payloads, direct reaction/liked payload rendering, inline image scaling, fake server-mode joins, and controlled TikTok-like target routing. Did not test OBS, hosted page, real extension runtime, real VDO bridge, real relay delivery, live TikTok/platform behavior, standalone app, or long-running persistence. | | 2026-06-24 | Codex | Multi-alerts controlled browser validation attempt | Runtime browser validation attempt | `17-runtime-validation-evidence-log.md`, `07-overlays-and-pages/multi-alerts.md`, `07-overlays-and-pages/page-capability-matrix.md`, checklist/ledger/audit/index updates | validation-failed | Ran `node scripts/playwright-multi-alerts-overlay-e2e.cjs`; result failed with `frame.waitForFunction: Timeout 30000ms exceeded` at `waitForPreviewFrame` while waiting for the preview iframe to expose `window.__multiAlertsOverlay.getSettings`. Do not promote multi-alert render, queue, filter, audio, or server-mode behavior to browser-validated from this run. | diff --git a/docs/agents/02-resource-processing-ledger.md b/docs/agents/02-resource-processing-ledger.md index acc88708c..4aab5fc4c 100644 --- a/docs/agents/02-resource-processing-ledger.md +++ b/docs/agents/02-resource-processing-ledger.md @@ -32,7 +32,7 @@ Use this file to answer: "Has this resource been processed already, and how deep | Resource Area | Current Depth | Main Output Docs | Remaining Need | | --- | --- | --- | --- | | Overall objective coverage/readiness | heavy audit plus narrow runtime and focused validation evidence | `15-objective-coverage-and-readiness-audit.md`, `99-agent-index.md`, `14-validation-and-refresh-roadmap.md`, `16-runtime-validation-playbooks.md`, `17-runtime-validation-evidence-log.md`, `18-focused-validation-evidence-log.md` | Keep coverage current after new passes; do not mark the whole docs objective complete until runtime-tested claims and proof gaps are resolved. Use the runtime playbooks to record evidence before promoting claims. | -| Agent documentation navigation | quick/focused docs audit plus static viewer/sitemaps | `docs/index.html`, `docs/agents/SITEMAP.md`, section `docs/agents/*/SITEMAP.md` files, `19-navigation-and-link-audit.md`, `99-agent-index.md`, `AGENT.md`, section indexes | Static client-side Markdown viewer added at `docs/index.html`; root and per-section sitemap Markdown files added under `docs/agents`. Current focused audit covers 161 Markdown files with zero unreferenced non-template pages, zero broken exact agent-doc Markdown refs, and zero ambiguous bare section-index filenames. Refresh after sitemap changes and large doc-growth. | +| Agent documentation navigation | quick/focused docs audit plus static viewer/sitemaps | `docs/index.html`, `docs/agents/SITEMAP.md`, section `docs/agents/*/SITEMAP.md` files, `19-navigation-and-link-audit.md`, `99-agent-index.md`, `AGENT.md`, section indexes | Static client-side Markdown viewer added at `docs/index.html`; root and per-section sitemap Markdown files added under `docs/agents`. Current focused audit covers 162 Markdown files with zero unreferenced non-template pages, zero broken exact agent-doc Markdown refs, and zero ambiguous bare section-index filenames. Refresh after sitemap changes and large doc-growth. | | Runtime validation workflow | heavy planning plus evidence log | `14-validation-and-refresh-roadmap.md`, `16-runtime-validation-playbooks.md`, `17-runtime-validation-evidence-log.md`, `12-development/testing-and-validation.md` | Continue executing playbooks and recording real runtime evidence before promoting commands, URL options, sources, app flows, OBS pages, integrations, provider behavior, or support claims to tested. | | Existing test and validation assets | heavy inventory/routing plus focused config/metadata/Node/browser-fixture evidence | `12-development/test-asset-matrix.md`, `12-development/testing-and-validation.md`, `16-runtime-validation-playbooks.md`, `18-focused-validation-evidence-log.md` | Focused evidence now covers settings config JSON validation, generated settings/URL/public-site metadata checks with duplicate metadata findings, selected Event Flow internals, Twitch subgift normalization, AI prompt builder smoke behavior, profanity/moderation checks, local browser model registry checks, OpenCode Zen fallback checks, Kokoro and Kitten static TTS asset wiring, Transformers remote-host defaults, RAG fixture E2E/benchmark behavior, plus a failing Piper asset expectation. Keep the matrix current when npm aliases, Node tests, browser fixtures, shell validators, metadata checkers, or Playwright scripts change; run focused assets before using them as evidence. | | Product overview and install surfaces | heavy | `01-product-map.md`, `02-installation-and-surfaces.md`, `13-reference/app-extension-mode-crosswalk.md`, `13-reference/install-update-version-guide.md`, `13-reference/public-claims-boundary-matrix.md` | Intense claim reconciliation only if publishing user-facing final docs; app auto-update and exact extension export/import behavior still need verification. | @@ -44,7 +44,7 @@ Use this file to answer: "Has this resource been processed already, and how deep | URL/page routing and parameters | heavy plus source trace/inventory/crosswalk and focused generated metadata validation | `13-reference/control-surface-crosswalk.md`, `13-reference/workflow-setup-decision-tree.md`, `13-reference/preflight-checklists.md`, `13-reference/surface-url-cheatsheet.md`, `07-overlays-and-pages/page-capability-matrix.md`, `13-reference/url-parameters.md`, `13-reference/url-parameter-index.md`, `13-reference/url-option-examples.md`, `13-reference/url-parameter-source-trace.md`, `13-reference/root-page-url-parameter-matrix.md`, `13-reference/subpage-url-parameter-matrix.md` | `shared/config/urlParameters.js` focused metadata validation confirmed 255 generated URL parameter items, 23 sections, 2 groups, 302 lookup entries, and no missing required URL parameter fields. Findings remain for duplicate `password` aliases and normalized `strokecolor` aliases. Remaining needs: runtime validation of page-specific support outside the generated `dock.html` index, exact page/channel validation, theme/game/source-page parameter behavior, and browser/OBS validation of example behavior before final publication. | | Terminology/glossary | heavy | `13-reference/glossary.md` | UI-label and support-transcript synonym pass. | | Public supported sites and source files | heavy inventory/status plus public implementation map and focused public-card metadata validation | `08-platform-sources/source-inventory.md`, `supported-sites-lookup.md`, `public-site-support-status.md`, `public-site-implementation-map.md`, `source-file-processing-matrix.md`, `manifest-content-scripts.md`, `manifest-row-matrix.md` | `docs/js/sites.js` focused metadata validation confirmed 139 public site cards and no missing required fields, with a duplicate normalized `On24`/`ON24` card finding. Remaining needs: runtime health validation, duplicate/stale-card reconciliation, and quick notes for newly added files. | -| High-volume platform pages and capability routing | heavy plus focused Twitch provider evidence | YouTube, TikTok, Twitch, Kick, Rumble, Facebook, Instagram, Discord docs, `08-platform-sources/platform-capability-matrix.md`, `18-focused-validation-evidence-log.md` | Twitch subgift provider normalization has focused Node-test evidence only. Remaining needs: intense parser/event/auth/send-chat/app-parity validation and live platform checks. | +| High-volume platform pages and capability routing | heavy plus focused Twitch provider evidence | YouTube, TikTok, Twitch, Kick, Rumble, Facebook, Instagram, Discord docs, `08-platform-sources/priority-platform-answer-matrix.md`, `08-platform-sources/platform-capability-matrix.md`, `18-focused-validation-evidence-log.md` | Priority support phrasing now has a dedicated matrix. Twitch subgift provider normalization has focused Node-test evidence only. Remaining needs: intense parser/event/auth/send-chat/app-parity validation and live platform checks. | | Other platform sources | grouped quick/heavy passes | `02-resource-manifest.md`, `08-platform-sources/source-inventory.md`, `08-platform-sources/manual-static-and-helper-sources.md`, `08-platform-sources/websocket-source-pages.md`, `08-platform-sources/communication-and-sensitive-sources.md`, `08-platform-sources/embedded-chat-widget-sources.md`, `08-platform-sources/live-commerce-sources.md`, `08-platform-sources/webinar-and-event-sources.md`, `08-platform-sources/creator-live-cam-sources.md`, `08-platform-sources/popout-chat-only-sources.md`, `08-platform-sources/event-and-community-sources.md`, `08-platform-sources/independent-live-platform-sources.md`, `08-platform-sources/video-broadcast-platform-sources.md`, `08-platform-sources/community-membership-webapp-sources.md`, `08-platform-sources/regional-and-emerging-platform-sources.md`, `08-platform-sources/special-case-platform-and-helper-sources.md` | Live/browser validation and intense passes for fragile/high-risk platforms. | | Overlays and tool pages | heavy plus file-level ledger plus narrow browser validation evidence | `07-overlays-and-pages/*`, especially `page-capability-matrix.md`, `page-processing-matrix.md`, `diagnostic-helper-pages.md`, `game-pages.md`, `theme-pages.md`, and `17-runtime-validation-evidence-log.md` | `scoreboard.html` has controlled local browser validation for preview/local scoring only. `reactions.html` has controlled local browser validation for popup URL parsing, synthetic bridge/payload rendering, fake server-mode joins, and controlled TikTok-like target routing only. `multi-alerts.html` has a failed validation attempt waiting for the preview iframe overlay API. Remaining needs: per-page command handlers, storage, OBS behavior, channel/label behavior, controlled payload samples for other pages, game/theme rendering validation, import/export validation, replay validation, and broader test coverage. | | API and integrations | heavy plus source trace/crosswalk plus focused examples consistency check | `09-api-and-integrations/*`, `13-reference/control-surface-crosswalk.md`, `13-reference/action-command-index.md`, `13-reference/command-action-source-trace.md`, `13-reference/api-command-validation-matrix.md`, `13-reference/api-command-examples.md`, `18-focused-validation-evidence-log.md` | Static examples extraction found 29 action examples and, after docs updates, zero missing entries across action index, validation matrix, and source trace; `content4`/numbered channel caveats were added to the matrix and trace. Remaining needs: runtime command validation, callback/label/channel validation, and integration edge cases. | @@ -135,7 +135,7 @@ These resources have been mined enough to support heavy agent docs, but not enou | Event/community sources | `sources/arenasocial.js`, `buzzit.js`, `cime.js`, `gala.js`, `linkedin.js`, `livepush.js`, `megaphonetv.js`, `quickchannel.js`, `slido.js`, `tradingview.js` | `08-platform-sources/event-and-community-sources.md` | Live validation for Slido question rows, CI.ME donation/viewer data, Arena Social viewer counts, LivePush relayed source types, LinkedIn path gating, and MegaphoneTV source identity. | | Regional/emerging platform sources | `sources/bilibili.js`, `bilibilicom.js`, `favorited.js`, `kwai.js`, `pilled.js`, `portal.js`, `pumpfun.js`, `retake.js`, `rooter.js`, `shareplay.js`, `soulbound.js`, `streamplace.js`, `substack.js`, `tikfinity.js`, `uscreen.js`, `vklive.js`, `xeenon.js` | `08-platform-sources/regional-and-emerging-platform-sources.md` | Live validation for Bilibili URL variants, SharePlay shoutout/Blitz cards, Tikfinity feed payloads, Stream.place relayed rows, Substack live URL routing, Pump.fun/Retake tips, SoulBound manifest routing, and inactive viewer helpers. | | Special-case platform/helper sources | `sources/joystick.js`, `velora.js`, `vercel.js`, `verticalpixelzone.js`, `vpzone.js`, `x.js`, `youtube_comments.js`, `youtube_static.js` | `08-platform-sources/special-case-platform-and-helper-sources.md` | Live validation for Joystick/Velora/VPZone mode split, Vertical Pixel Zone selectors/source identity, X live URL variants, Vercel demo session sharing, and top-level YouTube helper load status. | -| Cross-platform capability routing | Platform docs, source inventory, manifest matrices, reference pages | `08-platform-sources/platform-capability-matrix.md` | Send-chat, moderation, event-family, app-parity, and exact payload validation. | +| Cross-platform capability routing | Platform docs, source inventory, manifest matrices, reference pages | `08-platform-sources/platform-capability-matrix.md`, `08-platform-sources/priority-platform-answer-matrix.md` | Send-chat, moderation, event-family, app-parity, and exact payload validation. | ### Remaining Platform Source Routing diff --git a/docs/agents/08-platform-sources/SITEMAP.md b/docs/agents/08-platform-sources/SITEMAP.md index b36b2ec7c..792da05d2 100644 --- a/docs/agents/08-platform-sources/SITEMAP.md +++ b/docs/agents/08-platform-sources/SITEMAP.md @@ -26,6 +26,7 @@ Use this file to navigate this folder without scanning the filesystem. - [Manifest Row Matrix](../08-platform-sources/manifest-row-matrix.md) - This page lists every current manifest.json content-script entry. Use it when answering whether a URL shape has an extension content-script match and which file loads first. The manifest remains the source of truth; public site/type hints are agent-routing hints, not final support proof. - [Manual, Static, And Helper Sources](../08-platform-sources/manual-static-and-helper-sources.md) - Use this page when a file in sources/static/, sources/inject/, or a helper-like sources/*.js row appears in the source matrix and the question is "is this a normal chat source?" - [Platform Capability Matrix](../08-platform-sources/platform-capability-matrix.md) - Use this page when an agent needs to answer "does SSN support this platform feature?" quickly. This is a routing matrix, not the final line-level source of truth. Before making a public or support-critical promise, check the linked platform doc and the current source. +- [Priority Platform Answer Matrix](../08-platform-sources/priority-platform-answer-matrix.md) - Use this page for safe support phrasing and first checks for YouTube, TikTok, Twitch, Kick, Rumble, Facebook, Instagram, and Discord. - [Popout And Chat-Only Sources](../08-platform-sources/popout-chat-only-sources.md) - Use this page for smaller supported platforms where the required setup is a popout, chat-only, or platform-specific chat URL. These are rendered DOM chat captures unless noted otherwise. - [Public Site Implementation Map](../08-platform-sources/public-site-implementation-map.md) - Use this page when a user asks whether a listed site is supported and the answer needs the current source route, manifest row, or grouped platform doc. - [Public Site Support Status](../08-platform-sources/public-site-support-status.md) - Use this page to decide how strong an answer can be when a user asks whether a site is supported. This page does not replace the full site list in supported-sites-lookup.md; it explains what a public listing means and what still needs source verification. diff --git a/docs/agents/08-platform-sources/index.md b/docs/agents/08-platform-sources/index.md index e30a66503..b752ccd01 100644 --- a/docs/agents/08-platform-sources/index.md +++ b/docs/agents/08-platform-sources/index.md @@ -6,6 +6,8 @@ Status: framework plus heavy passes for source inventory, supported-site lookup, This section tracks platform-specific source capture behavior. +For support-facing high-volume platform questions, start with `priority-platform-answer-matrix.md` before making exact claims about rich events, send-back, app parity, or mode-specific behavior. + ## High-Priority Pages - `source-inventory.md`: heavy inventory pass started. @@ -17,6 +19,7 @@ This section tracks platform-specific source capture behavior. - `manifest-content-scripts.md`: manifest source-load matrix and special content-script flags. - `manifest-row-matrix.md`: full 155-row content-script matrix with script, bucket, match count, flags, sample pattern, and public routing hints. - `platform-capability-matrix.md`: high-value platform and setup-type capability routing for chat capture, rich events, send-back, app differences, and support triage. +- `priority-platform-answer-matrix.md`: safe support phrasing, first checks, and no-overclaim routing for YouTube, TikTok, Twitch, Kick, Rumble, Facebook, Instagram, and Discord. - `youtube.md`: heavy extraction pass complete. - `tiktok.md`: heavy extraction pass complete. - `tiktok-standalone-app.md`: app-specific TikTok connector, signing, fallbacks, replies, event families, tests, and support triage. diff --git a/docs/agents/08-platform-sources/platform-capability-matrix.md b/docs/agents/08-platform-sources/platform-capability-matrix.md index cd193bb4c..a8e8b1b53 100644 --- a/docs/agents/08-platform-sources/platform-capability-matrix.md +++ b/docs/agents/08-platform-sources/platform-capability-matrix.md @@ -4,6 +4,8 @@ Status: heavy synthesis pass from current agent platform docs, source inventory, Use this page when an agent needs to answer "does SSN support this platform feature?" quickly. This is a routing matrix, not the final line-level source of truth. Before making a public or support-critical promise, check the linked platform doc and the current source. +For support-facing short answers about YouTube, TikTok, Twitch, Kick, Rumble, Facebook, Instagram, and Discord, start with `priority-platform-answer-matrix.md` before using the broader matrix below. + ## Source Anchors - `docs/agents/08-platform-sources/youtube.md` @@ -34,6 +36,7 @@ Use this page when an agent needs to answer "does SSN support this platform feat - `docs/agents/08-platform-sources/supported-sites-lookup.md` - `docs/agents/08-platform-sources/manifest-content-scripts.md` - `docs/agents/08-platform-sources/manifest-row-matrix.md` +- `docs/agents/08-platform-sources/priority-platform-answer-matrix.md` - `docs/agents/13-reference/feature-support-decision-matrix.md` - `docs/agents/13-reference/modes-and-capability-matrix.md` - `docs/event-reference.html` diff --git a/docs/agents/08-platform-sources/priority-platform-answer-matrix.md b/docs/agents/08-platform-sources/priority-platform-answer-matrix.md new file mode 100644 index 000000000..ceaf8a5ec --- /dev/null +++ b/docs/agents/08-platform-sources/priority-platform-answer-matrix.md @@ -0,0 +1,262 @@ +# Priority Platform Answer Matrix + +Status: heavy source-routing pass on 2026-06-24. This page is source-backed orientation from current platform docs plus focused source greps for send-back, source-control, auth, and event terms. It is not live platform testing. + +## Purpose + +Use this page when a user asks a high-volume platform question and needs a safe support answer quickly: + +- Does YouTube, TikTok, Twitch, Kick, Rumble, Facebook, Instagram, or Discord work? +- Which mode should I use for this platform? +- Does it support follows, gifts, raids, rewards, viewer counts, moderation, or send-back? +- Why does app mode differ from browser extension mode? +- What should I ask before escalating a platform bug? + +This page sits between: + +- `supported-sites-lookup.md` for public site-card/setup lookup. +- `public-site-support-status.md` for what a public listing does and does not prove. +- `platform-capability-matrix.md` for broader cross-platform capability routing. +- Individual platform docs for current source-backed details. +- `../13-reference/app-extension-mode-crosswalk.md` for app-vs-extension caveats. +- `../13-reference/public-claims-boundary-matrix.md` for broad public wording boundaries. + +## Source Scan Anchors + +This pass checked the current docs plus source terms in: + +- `sources/youtube.js`, `sources/websocket/youtube.js`, `providers/youtube/liveChat.js` +- `sources/tiktok.js`, `C:\Users\steve\Code\ssapp\tiktok\connection-manager.js` +- `sources/twitch.js`, `sources/websocket/twitch.js`, `providers/twitch/chatClient.js` +- `sources/kick.js`, `sources/kick_new.js`, `sources/websocket/kick.js`, `providers/kick/core.js` +- `sources/rumble.js`, `sources/websocket/rumble.js` +- `sources/facebook.js`, `sources/websocket/facebook.js` +- `sources/instagram.js`, `sources/instagramlive.js`, `sources/instafeed.js` +- `sources/discord.js` + +Terms checked included `SEND_MESSAGE`, `SOURCE_CONTROL`, `sendMessage`, `sendChat`, `viewer_update`, `new_follower`, `subscription_gift`, `reward`, `raid`, `user_banned`, token/auth terms, and platform-specific bridge terms. + +## Safe Answer Matrix + +| Platform | First Safe Answer | Best Mode To Check First | Do Not Promise Without More Proof | First Follow-Up Question | +| --- | --- | --- | --- | --- | +| YouTube | Yes, SSN supports YouTube through rendered live chat and a richer WebSocket/Data API source path. | Normal visible chat: DOM live chat/popout. Richer API events: WebSocket/Data API page. | Send-back, delete, ban, moderation, subscriber alerts, redirects through API, or app parity. | Are you using normal live chat/popout, Studio chat, or the YouTube WebSocket/API source page? | +| TikTok | Yes, but TikTok is fragile and mode-specific. The standalone app has the broadest TikTok mode set. | App users: TikTok app connector modes. Browser users: standard DOM mode. | Replies, complete gift dedupe, live availability, exact event parity, or sign-server reliability. | Are you using the app or extension, and which TikTok mode: Standard, WS Auto, Local Signer, Polling, or TikFinity? | +| Twitch | Yes, visible chat works through DOM capture; richer events need WebSocket/EventSub/provider mode and OAuth scopes. | Normal chat: DOM/popout. Follows, raids, rewards, subs, moderation: WebSocket/EventSub. | Channel points, moderation, send-back, ads, follows, or subscriber data without checking scopes/role. | Do you need only visible chat, or EventSub features like rewards, raids, subs, follows, or moderation? | +| Kick | Yes, normal Kick chat can be captured, but structured rewards, follows, subs, raids, tips, moderation, and send-back are bridge/OAuth work. | Normal chat: current popout chat URL. Rich events/send-back: Kick WebSocket bridge. | Chat sending, reward events, OAuth health, CAPTCHA behavior, or `kick.js` vs `kick_new.js` runtime load. | Are you using `https://kick.com/popout/CHANNEL/chat` or the Kick bridge source page? | +| Rumble | Yes, through normal DOM capture and a read-only Rumble Live Stream API bridge. | Creator/API workflow: Rumble API bridge. Viewer/page workflow: DOM page capture. | Sending chat through the Rumble API bridge; it is documented as read-only in current source. | Are you using the private Rumble Live Stream API URL or just a normal Rumble page? | +| Facebook | Yes, but viewer DOM capture and managed Page Graph API bridge are different workflows. | Page owner/admin: Graph API bridge. Viewer/browser workflow: DOM page capture. | Graph token permissions, viewer count, Page role behavior, app OAuth, or Stars parity. | Are you viewing as a normal viewer or managing the Page/live video as the owner/admin? | +| Instagram | Limited DOM capture is supported for Instagram Live and feed/post/comment capture. | Live chat: Instagram Live DOM page. Feed/comments: normal Instagram page with visible comments. | Send-back, API/headless capture, membership/donation fields, or app parity. | Is this Instagram Live chat or regular feed/post/comment capture? | +| Discord | SSN captures visible Discord web messages from the web app. It is not a Discord bot/API integration. | Web Discord page with `/channels/` URL and the source enabled. | Discord bot behavior, roles/moderation, direct-message automation, or send-back. | Is the Discord web page open on the exact channel, and is any custom channel filter enabled? | + +## Event And Send-Back Cheat Sheet + +| User Asks | Safer Answer | Check Next | +| --- | --- | --- | +| Can SSN send chat back to YouTube? | Maybe. YouTube source-control/send behavior is mode- and auth-specific, so do not answer from capture support alone. | `youtube.md`, `sources/websocket/youtube.js`, `providers/youtube/liveChat.js` | +| Can SSN reply to TikTok? | Sometimes. TikTok replies require a suitable app/source mode and a signed-in session; reading can work while replies fail. | `tiktok.md`, `tiktok-standalone-app.md`, app `connection-manager.js` | +| Can SSN send Twitch chat? | WebSocket/provider mode has send-message paths, but the client must be connected to the right channel with OAuth and role/scope coverage. | `twitch.md`, `sources/websocket/twitch.js`, `providers/twitch/chatClient.js` | +| Can SSN send Kick chat? | The Kick bridge has send paths when OAuth tokens/scopes are valid; DOM capture alone is not the send path. | `kick.md`, `sources/websocket/kick.js` | +| Can SSN send Rumble chat? | No for the documented Rumble API bridge in current notes; it logs read-only behavior for send attempts. | `rumble.md`, `sources/websocket/rumble.js` | +| Can SSN send Facebook/Instagram/Discord messages? | Do not promise. Current docs describe capture paths, not a verified send-back integration for these surfaces. | `facebook.md`, `instagram.md`, `discord.md`, current source | +| Does a platform support rewards/channel points? | Twitch and Kick have structured reward paths in richer source modes; normal DOM capture may only see visible text. | `twitch.md`, `kick.md`, Event Flow docs | +| Does a platform support follows/raids/subs/gifts? | Often yes only in richer source/API modes or when the platform renders a visible system row. Check mode and source. | `platform-capability-matrix.md`, individual platform doc | +| Does a platform support viewer counts? | Sometimes, gated by settings/source mode/API availability. Treat viewer counts as optional and platform-limited. | individual platform doc and source | +| Does a platform support moderation/delete/ban? | This is high risk. It needs source-control, OAuth/scopes, role, and live validation before a strong answer. | `api-command-validation-matrix.md`, platform source | + +## Platform-Specific Safe Phrasing + +### YouTube + +Safe: + +```text +YouTube support depends on the capture mode. Use the normal live chat/popout for rendered chat. Use the WebSocket/Data API source page for richer API-backed events. Do not assume send-back, delete, ban, moderation, or subscriber alerts work unless that mode and auth path are verified. +``` + +Ask: + +- Is the stream live? +- Is the user using a watch URL, live chat popout, Studio chat, or WebSocket/Data API page? +- Does the dock receive messages before OBS is involved? +- Are they expecting normal chat, gifts/memberships, viewer counts, moderation, or send-back? + +Do not say: + +- "YouTube API mode exposes every DOM event." +- "Subscriber alerts are instant." +- "YouTube capture means YouTube send-back works." + +### TikTok + +Safe: + +```text +TikTok is mode-sensitive. The extension DOM path reads rendered TikTok Live rows. The standalone app has broader connector/signing modes and reply paths, but replies still need the right mode and a signed-in session. +``` + +Ask: + +- App or extension? +- Which mode: Standard, WS Auto, Local Signer, Polling, or TikFinity? +- Is the TikTok account actually live? +- Does reading fail, or only replies? +- Is the app version current? + +Do not say: + +- "TikTok WS always works." +- "If reading works, replies will work." +- "TikFinity fallback supports replies." + +### Twitch + +Safe: + +```text +Twitch visible chat can work in DOM mode. Follows, raids, channel points, subs, bits, deletes, bans, ads, and stronger event support belong to WebSocket/EventSub/provider mode and depend on OAuth scopes and channel role. +``` + +Ask: + +- DOM chat or WebSocket/EventSub? +- Broadcaster, moderator, or viewer account? +- Which event is missing? +- Did sign-in grant the needed scopes? + +Do not say: + +- "DOM capture gives full EventSub support." +- "Channel points work without broadcaster authorization." +- "Send chat works without a connected Twitch chat client." + +### Kick + +Safe: + +```text +Use Kick popout chat for visible chat. Use the Kick bridge source page for structured rewards, follows, subs, raids, KICKs/tips, moderation events, and chat sending. OAuth/CAPTCHA and token state can change the result. +``` + +Ask: + +- Popout chat or bridge source page? +- Same SSN session as dock/Flow Actions? +- Signed in with Kick and connected channel? +- CAPTCHA/human verification shown? +- Exact reward title if Event Flow is involved? + +Do not say: + +- "Opening Kick chat is enough for channel point events." +- "Kick OAuth will behave the same in Chrome and the app." +- "DOM capture is the reliable send-chat path." + +### Rumble + +Safe: + +```text +Rumble has normal DOM capture and a Rumble Live Stream API bridge. The API bridge is read-only in current docs/source, but it is the structured path for chat, rants, followers, subscribers, gifted subs, viewer counts, and stream status. +``` + +Ask: + +- Normal page or API bridge? +- Is the private API URL pasted into the bridge page? +- Is the stream active? +- Is replay enabled and causing old messages? + +Do not say: + +- "Rumble API mode can send chat." +- "The private API URL is safe to share publicly." + +### Facebook + +Safe: + +```text +Facebook support depends on whether this is visible DOM capture or managed Page Graph API bridge. Page-token/API behavior depends on Page role, token permissions, live video ID, and current Graph API behavior. +``` + +Ask: + +- Viewer page or managed Page workflow? +- Page owner/admin or normal viewer? +- Live video ID known? +- Is the token expired or missing permissions? +- Are comments visible in the opened page? + +Do not say: + +- "Any Facebook viewer can use the Page API bridge." +- "DOM capture and Graph API mode expose the same data." +- "Stars/viewer counts are guaranteed." + +### Instagram + +Safe: + +```text +Instagram support is DOM capture for visible live/feed/comment content. It is not a verified headless or API bridge. Live join events require visible rows and the join-event setting. +``` + +Ask: + +- Live or feed/post/comments? +- Are messages visibly appearing? +- Is the page logged in and loaded? +- Are join events expected, and is `capturejoinedevent` enabled? + +Do not say: + +- "Instagram send-back is supported." +- "Instagram API capture is built in." +- "Live and feed capture use identical downstream source types." + +### Discord + +Safe: + +```text +Discord support means DOM capture from the Discord web app. It watches visible web messages on `/channels/` URLs. It is not a Discord bot/API integration. +``` + +Ask: + +- Is Discord open in the browser/app source window on a `/channels/` URL? +- Is the Discord source setting enabled? +- Is a custom channel filter configured? +- Are messages visible and new after source load? + +Do not say: + +- "SSN has a Discord bot." +- "Discord roles/moderation are exposed." +- "Discord send-back is supported." + +## Escalation Rules + +Escalate or source-check before giving a final answer when: + +- The user needs send-back, moderation, deletes, bans, or API write behavior. +- The user needs follows, raids, rewards, gifts, tips, viewer counts, or purchases to trigger automation. +- The behavior differs between app and extension. +- The source depends on OAuth, loopback auth, CAPTCHA, platform tokens, or a private API URL. +- The user says the public site list proves a feature should work. +- The platform recently changed layout, login policy, API access, or event names. + +## Answer Template + +```text +Short answer: [yes/no/depends]. For [platform], [feature] depends on [mode/auth/source]. Start with [best mode/setup]. Do not assume [common overclaim]. If this needs a final support answer, verify [exact source/doc/runtime evidence]. +``` + +## Follow-Up Needs + +- Line-level source-control/send-back validation for YouTube, Twitch, Kick, and TikTok app paths. +- Runtime browser/app checks for top-platform DOM capture versus WebSocket/API source-page behavior. +- OAuth/scope/role validation for YouTube, Twitch, Kick, and Facebook. +- App parity validation for each priority platform. +- Support-history refresh focused on platform-specific current failures, without copying raw support transcripts. diff --git a/docs/agents/11-support-kb/common-question-coverage-map.md b/docs/agents/11-support-kb/common-question-coverage-map.md index 40ab62717..e7232b634 100644 --- a/docs/agents/11-support-kb/common-question-coverage-map.md +++ b/docs/agents/11-support-kb/common-question-coverage-map.md @@ -48,8 +48,8 @@ For plain-language user wording and first-route selection, use `question-intent- | Why does the supported-site list not prove every feature works? | covered-heavy | `08-platform-sources/public-site-support-status.md` | `08-platform-sources/platform-capability-matrix.md` | | Which source file handles a public site card? | covered-heavy | `08-platform-sources/public-site-implementation-map.md` | `source-file-processing-matrix.md`, `manifest-content-scripts.md`, `manifest-row-matrix.md` | | What is the difference between standard DOM capture, popout capture, static helper, injected helper, and WebSocket/API source page? | covered-heavy | `13-reference/modes-and-capability-matrix.md` | `08-platform-sources/manual-static-and-helper-sources.md`, `websocket-source-pages.md` | -| Does a platform support gifts, tips, raids, rewards, follows, viewer counts, or moderation events? | mixed, needs-intense | `08-platform-sources/platform-capability-matrix.md` | exact platform doc and current source | -| Can SSN send chat back to a platform? | mixed, needs-intense | `08-platform-sources/platform-capability-matrix.md` | `websocket-source-pages.md`, exact platform source | +| Does a platform support gifts, tips, raids, rewards, follows, viewer counts, or moderation events? | mixed, needs-intense | `08-platform-sources/priority-platform-answer-matrix.md` | `08-platform-sources/platform-capability-matrix.md`, exact platform doc, and current source | +| Can SSN send chat back to a platform? | mixed, needs-intense | `08-platform-sources/priority-platform-answer-matrix.md` | `platform-capability-matrix.md`, `websocket-source-pages.md`, exact platform source | | Can SSN capture private chats, meetings, or assistant pages? | covered-heavy, needs-live-validation | `08-platform-sources/communication-and-sensitive-sources.md` | privacy/toggle/source checks | | Are helper files real chat parsers? | covered-heavy | `08-platform-sources/manual-static-and-helper-sources.md` | `08-platform-sources/special-case-platform-and-helper-sources.md` | | How do Joystick, Velora, VPZone, X, Vertical Pixel Zone, Vercel helper, or top-level YouTube helper copies fit? | covered-heavy, needs-live-validation | `08-platform-sources/special-case-platform-and-helper-sources.md` | exact source file and manifest row | diff --git a/docs/agents/11-support-kb/common-question-fast-path.md b/docs/agents/11-support-kb/common-question-fast-path.md index 198a5eaa5..cdd207aeb 100644 --- a/docs/agents/11-support-kb/common-question-fast-path.md +++ b/docs/agents/11-support-kb/common-question-fast-path.md @@ -38,8 +38,8 @@ This page is intentionally compact. It points to the deeper docs rather than res | "How many sites are supported?" | The public site list is large and current docs route 139 public cards from the latest extraction, but focused metadata validation found duplicate `On24`/`ON24` cards and exact site health/feature support still need source/mode checks. | `08-platform-sources/supported-sites-lookup.md`, `08-platform-sources/public-site-support-status.md`, `13-reference/public-claims-boundary-matrix.md` | "Every listed site fully works right now." | | "Is this site supported?" | Check the public card, setup type, implementation map, and source/mode docs before answering. | `08-platform-sources/supported-sites-lookup.md`, `08-platform-sources/public-site-implementation-map.md`, exact platform doc | "Supported means all features work." | | "Why is a listed site broken?" | A public listing is a setup route, not runtime proof; confirm exact URL, mode, source visibility, manifest/source load, and recent platform changes. | `08-platform-sources/public-site-support-status.md`, exact source file | "The list proves it cannot be broken." | -| "Can it send chat back?" | Maybe, depending on platform, source mode, login/auth, permissions, and current implementation. | `08-platform-sources/platform-capability-matrix.md`, `08-platform-sources/websocket-source-pages.md`, exact platform source | "Yes, because chat capture works." | -| "Does it support gifts, raids, rewards, follows, or viewer counts?" | Often platform/mode-specific; use capability docs as orientation and source-check the exact event family. | `08-platform-sources/platform-capability-matrix.md`, platform doc, Event Flow docs | "All supported sites expose rich events." | +| "Can it send chat back?" | Maybe, depending on platform, source mode, login/auth, permissions, and current implementation. | `08-platform-sources/priority-platform-answer-matrix.md`, `08-platform-sources/platform-capability-matrix.md`, `08-platform-sources/websocket-source-pages.md`, exact platform source | "Yes, because chat capture works." | +| "Does it support gifts, raids, rewards, follows, or viewer counts?" | Often platform/mode-specific; use priority/capability docs as orientation and source-check the exact event family. | `08-platform-sources/priority-platform-answer-matrix.md`, `08-platform-sources/platform-capability-matrix.md`, platform doc, Event Flow docs | "All supported sites expose rich events." | | "Should I use extension or app?" | Use the extension for normal browser/cookie workflows; use the app for managed source windows or some throttling/source-window workflows. | `13-reference/app-extension-mode-crosswalk.md`, `13-reference/modes-and-capability-matrix.md`, `04-standalone-app-source-windows.md` | "The app fixes every login or platform problem." | | "Does the app behave like Chrome?" | Some behavior is shared, but Electron windows, sessions, source injection, OAuth handlers, and embedded login can differ. | `13-reference/app-extension-mode-crosswalk.md`, `04-standalone-app-source-windows.md`, `10-troubleshooting/desktop-app-issues.md` | "App and extension are identical." | | "What page do I open?" | Pick by job: source page for capture/API setup, dock for control, featured/theme pages for OBS output, sampleapi for command testing. | `13-reference/surface-url-cheatsheet.md`, `13-reference/workflow-setup-decision-tree.md` | "Always open dock only." | diff --git a/docs/agents/11-support-kb/question-intent-router.md b/docs/agents/11-support-kb/question-intent-router.md index 1a2f692a6..22e0087c6 100644 --- a/docs/agents/11-support-kb/question-intent-router.md +++ b/docs/agents/11-support-kb/question-intent-router.md @@ -19,6 +19,7 @@ This page complements: - `../13-reference/public-claims-boundary-matrix.md` for broad public wording such as 100+/120+ sites, two-way chat, no API keys, free/open-source, AI/TTS, app, plugin, services, and support promises. - `../13-reference/control-surface-crosswalk.md` for command/setting/URL/mode/plugin disambiguation. - `../13-reference/customization-path-decision-matrix.md` for ambiguous plugin/customization/source requests. +- `../08-platform-sources/priority-platform-answer-matrix.md` for safe high-volume platform phrasing before exact source validation. - `../13-reference/index.md` for broad reference routing. Rule: do not stop at this page for fragile claims. If the answer depends on selectors, exact platform support, send-back, auth, settings persistence, app parity, command payloads, or runtime behavior, open the routed topic doc and current source before giving a final-grade answer. @@ -41,8 +42,8 @@ Rule: do not stop at this page for fragile claims. If the answer depends on sele | "Is this site supported?" | Public site lookup | `../08-platform-sources/supported-sites-lookup.md` | Setup type and support-strength notes, not just the public card name. | | "Which source file handles this site?" | Implementation lookup | `../08-platform-sources/public-site-implementation-map.md` | Manifest row/source-page/stale-risk notes. | | "Why is a listed site broken?" | Supported-site caveat | `../08-platform-sources/public-site-support-status.md` | Exact URL, mode, current source, platform layout changes. | -| "Does this platform support raids/rewards/gifts/follows?" | Rich event support | `../08-platform-sources/platform-capability-matrix.md` | Exact platform doc and mode-specific source before promising. | -| "Can SSN send chat back?" | Send-back support | `../08-platform-sources/platform-capability-matrix.md` | Source mode, login/auth, permissions, send path, platform policy. | +| "Does this platform support raids/rewards/gifts/follows?" | Rich event support | `../08-platform-sources/priority-platform-answer-matrix.md` | Exact platform doc, capability matrix, and mode-specific source before promising. | +| "Can SSN send chat back?" | Send-back support | `../08-platform-sources/priority-platform-answer-matrix.md` | Source mode, login/auth, permissions, send path, platform policy. | | "This is a private chat/meeting/work app" | Sensitive source | `../08-platform-sources/communication-and-sensitive-sources.md` | Opt-in toggle, visible web panel, privacy redaction, no assumed send-back. | | "What source mode is this?" | Capture mode classification | `../13-reference/modes-and-capability-matrix.md` | DOM, popout, static/manual, injected helper, WebSocket/API source page, app window. | | "Which page should I open?" | Surface URL routing | `../13-reference/surface-url-cheatsheet.md` | Source page vs overlay page vs API test page vs diagnostic helper. | diff --git a/docs/agents/14-validation-and-refresh-roadmap.md b/docs/agents/14-validation-and-refresh-roadmap.md index 60b6c6f6c..177d64589 100644 --- a/docs/agents/14-validation-and-refresh-roadmap.md +++ b/docs/agents/14-validation-and-refresh-roadmap.md @@ -27,7 +27,7 @@ Current overlay runtime notes: `scoreboard.html` and `reactions.html` have narro Current focused validation notes: Event Flow custom JS, compare-property, template/counter, OBS system trigger, and play-media duration Node tests have focused evidence in `18-focused-validation-evidence-log.md`. Twitch subgift provider normalization, AI prompt builder smoke behavior, profanity/moderation static checks, local browser model registry checks, OpenCode Zen fallback checks, Kokoro asset wiring, Kitten TTS asset wiring, Transformers local defaults, RAG browser-fixture/benchmark behavior, settings config JSON validation, generated settings/URL/public-site metadata validation, and API command examples documentation consistency also have focused evidence there. Piper asset wiring has a failed focused test on an expected fallback remote-base string. The generated metadata check completed with duplicate URL alias findings for `password` and normalized `strokecolor`, plus duplicate public `On24`/`ON24` cards. The API examples consistency check found 29 extracted action examples and, after docs updates, zero missing entries across action index, validation matrix, and source trace, but it does not validate command behavior. These results do not validate Event Flow UI, Flow Actions overlay, OBS, app, extension, live platform behavior, browser audio, model runtime, real RAG uploads, live moderation quality, live LLM generation, generated overlay quality, provider calls, provider availability/pricing, popup/settings UI, generated docs UI, page-specific URL parsing, public supported-sites UI, API relay behavior, action callbacks, target labels, numbered content channels, or external integration behavior. -Current docs-navigation note: `19-navigation-and-link-audit.md` records a focused agent-doc navigation audit. The latest result found 161 Markdown files, zero unreferenced non-template pages, zero broken exact agent-doc Markdown references, and zero ambiguous bare section-index filenames. Re-run it after large documentation-growth, rename, or section-index changes. +Current docs-navigation note: `19-navigation-and-link-audit.md` records a focused agent-doc navigation audit. The latest result found 162 Markdown files, zero unreferenced non-template pages, zero broken exact agent-doc Markdown references, and zero ambiguous bare section-index filenames. Re-run it after large documentation-growth, rename, or section-index changes. ## Priority Queue diff --git a/docs/agents/15-objective-coverage-and-readiness-audit.md b/docs/agents/15-objective-coverage-and-readiness-audit.md index 59a13e2da..de7dd923f 100644 --- a/docs/agents/15-objective-coverage-and-readiness-audit.md +++ b/docs/agents/15-objective-coverage-and-readiness-audit.md @@ -37,7 +37,7 @@ Steve asked for comprehensive AI-focused documentation around: | --- | --- | --- | --- | | Agent workspace scope and rules | `AGENT.md`, `00-inventory-and-plan.md` | covered-heavy | Keep updated if write boundary or source priority changes. | | Resource inventory and extraction checklist | `02-resource-manifest.md`, `01-extraction-checklist.md`, `02-resource-processing-ledger.md` | covered-heavy | Continue adding pass rows after every new extraction/validation pass. | -| Agent-doc navigation and link hygiene | `docs/index.html`, `docs/agents/SITEMAP.md`, section `docs/agents/*/SITEMAP.md` files, `99-agent-index.md`, `AGENT.md`, `19-navigation-and-link-audit.md`, section indexes | covered-quick plus focused docs audit plus static viewer/sitemaps | Current audit covers 161 Markdown files with zero unreferenced non-template pages, zero broken exact agent-doc Markdown refs, and zero ambiguous bare section-index filenames. Browser smoke passed for default doc load, deep link load, section sitemap link traversal, raw link state, sidebar filter, and zero console errors. Re-run after major page additions, renames, or section index changes; current audit does not validate external/source links or all rendered anchors. | +| Agent-doc navigation and link hygiene | `docs/index.html`, `docs/agents/SITEMAP.md`, section `docs/agents/*/SITEMAP.md` files, `99-agent-index.md`, `AGENT.md`, `19-navigation-and-link-audit.md`, section indexes | covered-quick plus focused docs audit plus static viewer/sitemaps | Current audit covers 162 Markdown files with zero unreferenced non-template pages, zero broken exact agent-doc Markdown refs, and zero ambiguous bare section-index filenames. Browser smoke passed for default doc load, deep link load, section sitemap link traversal, raw link state, sidebar filter, and zero console errors. Re-run after major page additions, renames, or section index changes; current audit does not validate external/source links or all rendered anchors. | | Common question routing and evidence status | `11-support-kb/question-intent-router.md`, `11-support-kb/common-question-fast-path.md`, `11-support-kb/common-question-evidence-status.md`, `11-support-kb/common-question-test-set.md`, `11-support-kb/support-question-phrasebook.md`, `11-support-kb/common-question-coverage-map.md` | covered-heavy plus prompt benchmark | Add new paraphrased support wording after future QA exports and add runtime evidence only after actual validation. Use the test set to check common prompt routing and safe-answer behavior. | | Short support answers and response phrasing | `11-support-kb/support-answer-bank.md`, `support-response-playbook.md`, `support-macro-routing.md`, `support-intake-templates.md` | covered-heavy | Source-check fragile platform claims before sending final answers. | | Support-history evidence and stale-claim handling | `11-support-kb/mining-method.md`, `support-history-refresh-playbook.md`, `support-topic-frequency-index.md`, `historical-issues.md`, `support-evidence-ledger.md`, `unresolved-or-stale-claims.md`, `stevesbot-resource-inventory.md` | covered-heavy/frequency-pass plus repeatable refresh workflow | Promote or reject historical claims only after current source or runtime validation. Use the refresh playbook to rerun aggregate support-history counts without leaking raw support data. | @@ -47,7 +47,7 @@ Steve asked for comprehensive AI-focused documentation around: | App auth/sign-in issues | `10-troubleshooting/auth-and-sign-in.md`, `04-standalone-app-source-windows.md` | covered-heavy/source-backed | Validate OAuth callbacks, ports, external browser/profile behavior, and platform sign-in paths against current app runtime. | | Supported site list and setup type | `08-platform-sources/supported-sites-lookup.md`, `public-site-support-status.md`, `public-site-implementation-map.md`, `18-focused-validation-evidence-log.md` | covered-heavy/generated-source inventory plus focused metadata validation | Runtime health validation against real platform pages; reconcile stale/duplicate public cards, including duplicate `On24`/`ON24` metadata. | | Source file and manifest routing | `08-platform-sources/source-inventory.md`, `source-file-processing-matrix.md`, `manifest-content-scripts.md`, `manifest-row-matrix.md` | covered-heavy/generated-source inventory | Source-check newly added files and validate content-script behavior in browser/app. | -| Platform capability support | `08-platform-sources/platform-capability-matrix.md`, individual platform docs | covered-heavy/orientation | Intense validation for send-back, moderation, gifts, rewards, raids, follows, viewer counts, auth, and app parity. | +| Platform capability support | `08-platform-sources/priority-platform-answer-matrix.md`, `08-platform-sources/platform-capability-matrix.md`, individual platform docs | covered-heavy/orientation | Intense validation for send-back, moderation, gifts, rewards, raids, follows, viewer counts, auth, and app parity. | | Priority platforms | `youtube.md`, `tiktok.md`, `tiktok-standalone-app.md`, `twitch.md`, `kick.md`, `rumble.md`, `facebook.md`, `instagram.md`, `discord.md` | covered-heavy | Runtime and line-level validation for volatile auth/API/DOM/app-connector changes. | | Long-tail platform/source families | grouped `08-platform-sources/*.md` docs | covered-heavy/grouped | Browser/live validation for fragile DOM selectors and exact URL modes. | | Custom/generic sources | `08-platform-sources/generic-and-custom-sources.md`, `12-development/adding-a-source.md` | covered-heavy | Validate sample payloads and app/extension parity for new-source workflow. | @@ -120,7 +120,7 @@ The documentation objective should not be marked complete until current evidence 9. Runtime-tested claims have actual runtime evidence, not only static/source inspection. 10. Docs-only validation passes and no files outside the approved docs scope, `docs/index.html` plus `docs/agents`, were changed for the documentation work. -Items 1 through 8 are mostly covered. Item 6 now has focused docs-navigation audit support from `19-navigation-and-link-audit.md`, which found zero unreferenced non-template Markdown pages, zero broken exact agent-doc Markdown references, and zero ambiguous bare section-index filenames across 161 Markdown files. Items 9 and 10 must be rechecked at the end of every continuation. Item 9 remains the largest reason not to mark the full objective complete. +Items 1 through 8 are mostly covered. Item 6 now has focused docs-navigation audit support from `19-navigation-and-link-audit.md`, which found zero unreferenced non-template Markdown pages, zero broken exact agent-doc Markdown references, and zero ambiguous bare section-index filenames across 162 Markdown files. Items 9 and 10 must be rechecked at the end of every continuation. Item 9 remains the largest reason not to mark the full objective complete. Current runtime evidence is partial. As of 2026-06-24, `17-runtime-validation-evidence-log.md` records controlled local browser validation for `scoreboard.html` preview/local scoring behavior and `reactions.html` popup URL parsing, synthetic bridge/payload rendering, fake server-mode joins, and controlled TikTok-like target routing. It also records a failed `multi-alerts.html` validation attempt that timed out waiting for the preview iframe overlay API. This evidence does not validate OBS, hosted pages, the real extension/app bridge, live platform/source payloads, real WebSocket relay delivery, labels/password/session behavior outside the tested URLs, or long-running persistence. diff --git a/docs/agents/19-navigation-and-link-audit.md b/docs/agents/19-navigation-and-link-audit.md index 7b26101ac..0c282e8c5 100644 --- a/docs/agents/19-navigation-and-link-audit.md +++ b/docs/agents/19-navigation-and-link-audit.md @@ -30,7 +30,7 @@ Not audited as broken links: Read-only inline Node audit result: ```text -totalMarkdown: 161 +totalMarkdown: 162 orphanishCount: 0 localBrokenCount: 0 ambiguousBareSectionIndexCount: 0 diff --git a/docs/agents/99-agent-index.md b/docs/agents/99-agent-index.md index 7e201010d..03c395bb0 100644 --- a/docs/agents/99-agent-index.md +++ b/docs/agents/99-agent-index.md @@ -1,6 +1,6 @@ # SSN AI Documentation Index -Status: framework plus source-backed backbone, product/install, install/update/version, standalone app source-window parity, overlays, theme pages, individual game pages, tip jar/credits, AI/cohost pages, event/effect overlays, live display utilities, specialized/legacy pages, diagnostic/helper pages, page capability routing, page processing inventory, API/integrations, common FAQ, common question intent router, common question fast path, common question evidence status, common question test set, support question phrasebook, support macro routing, common question coverage map, objective coverage/readiness audit, common misconceptions/boundaries, public claims boundary matrix, diagnostic decision tree, workflow setup decision tree, validation/refresh roadmap, runtime validation playbook, runtime evidence log, focused validation evidence log, navigation/link audit, support KB index, support evidence ledger, support history refresh playbook, support topic frequency index, support response playbook, support intake templates, support answer bank, privacy/security, custom-source, customization path decision matrix, customization source trace, troubleshooting, priority platform, TikTok standalone app connector, remaining platform source, static/manual/helper sources, WebSocket/API source pages, communication/sensitive source scripts, embedded chat widget sources, live-commerce source scripts, webinar/event source scripts, creator-live-cam source scripts, popout/chat-only source scripts, event/community source scripts, independent live platform source scripts, video/broadcast platform source scripts, community/membership web-app source scripts, regional/emerging platform source scripts, special-case platform/helper source scripts, supported-site lookup/status/implementation map, source-file matrix, manifest row matrix, manifest source-load, platform capability matrix, Event Flow/Streamer.bot, first support-mining, desktop-app support, development/provider/test-asset, reference, control-surface crosswalk, action lookup, command source trace, API command validation matrix, API examples, URL option examples, URL parameter source trace, root page URL parameter matrix, subpage URL parameter matrix, settings, settings/session/storage source trace, settings change impact matrix, feature decision matrix, exact generated lookup, glossary, surface URL routing, how-to recipe, and preflight checklist passes. +Status: framework plus source-backed backbone, product/install, install/update/version, standalone app source-window parity, overlays, theme pages, individual game pages, tip jar/credits, AI/cohost pages, event/effect overlays, live display utilities, specialized/legacy pages, diagnostic/helper pages, page capability routing, page processing inventory, API/integrations, common FAQ, common question intent router, common question fast path, common question evidence status, common question test set, support question phrasebook, support macro routing, common question coverage map, objective coverage/readiness audit, common misconceptions/boundaries, public claims boundary matrix, diagnostic decision tree, workflow setup decision tree, validation/refresh roadmap, runtime validation playbook, runtime evidence log, focused validation evidence log, navigation/link audit, support KB index, support evidence ledger, support history refresh playbook, support topic frequency index, support response playbook, support intake templates, support answer bank, privacy/security, custom-source, customization path decision matrix, customization source trace, troubleshooting, priority platform answer matrix, TikTok standalone app connector, remaining platform source, static/manual/helper sources, WebSocket/API source pages, communication/sensitive source scripts, embedded chat widget sources, live-commerce source scripts, webinar/event source scripts, creator-live-cam source scripts, popout/chat-only source scripts, event/community source scripts, independent live platform source scripts, video/broadcast platform source scripts, community/membership web-app source scripts, regional/emerging platform source scripts, special-case platform/helper source scripts, supported-site lookup/status/implementation map, source-file matrix, manifest row matrix, manifest source-load, platform capability matrix, Event Flow/Streamer.bot, first support-mining, desktop-app support, development/provider/test-asset, reference, control-surface crosswalk, action lookup, command source trace, API command validation matrix, API examples, URL option examples, URL parameter source trace, root page URL parameter matrix, subpage URL parameter matrix, settings, settings/session/storage source trace, settings change impact matrix, feature decision matrix, exact generated lookup, glossary, surface URL routing, how-to recipe, and preflight checklist passes. ## Start Here @@ -15,7 +15,7 @@ Status: framework plus source-backed backbone, product/install, install/update/v - `16-runtime-validation-playbooks.md`: concrete runtime validation recipes and evidence templates for final-grade command, option, source, app, OBS, integration, AI/TTS, and support-claim validation. - `17-runtime-validation-evidence-log.md`: actual runtime validation evidence entries; currently includes controlled browser validation for `scoreboard.html` and `reactions.html`, plus a failed `multi-alerts.html` validation attempt. - `18-focused-validation-evidence-log.md`: focused validation evidence that is useful but not full runtime testing; currently includes settings config JSON, generated settings/URL/public-site metadata checks, Event Flow, Twitch provider, AI prompt builder, AI moderation, local model registry, provider fallback, local TTS, local AI asset, RAG fixture tests, and API command examples documentation consistency. -- `19-navigation-and-link-audit.md`: documentation navigation/link audit; current result is 161 Markdown files, zero unreferenced non-template pages, zero broken exact agent-doc Markdown references, and zero ambiguous bare section-index filenames. +- `19-navigation-and-link-audit.md`: documentation navigation/link audit; current result is 162 Markdown files, zero unreferenced non-template pages, zero broken exact agent-doc Markdown references, and zero ambiguous bare section-index filenames. ## Core Topic Pages @@ -30,7 +30,7 @@ Status: framework plus source-backed backbone, product/install, install/update/v ## Sections - `07-overlays-and-pages/index.md`: dock, featured, multi-alerts, theme pages, waitlist/polls/games, individual game pages, tip jar/credits, AI/cohost pages, event/effect overlays, live display utilities, specialized/legacy pages, diagnostic/helper pages, custom overlay, page capability routing, and page processing inventory passes started. -- `08-platform-sources/index.md`: source inventory, supported-site lookup/status/implementation map, source-file processing matrix, full manifest row matrix, manifest content-script matrix, platform capability matrix, plus YouTube, TikTok, TikTok standalone app connector, Twitch, Kick, Rumble, Facebook, Instagram, Discord, generic/custom, static/manual/helper source, WebSocket/API source-page, communication/sensitive source, embedded chat widget source, live-commerce source, webinar/event source, creator/live-cam source, popout/chat-only source, event/community source, independent live platform source, video/broadcast platform source, community/membership web-app source, regional/emerging platform source, and special-case platform/helper source passes started/complete. +- `08-platform-sources/index.md`: source inventory, supported-site lookup/status/implementation map, source-file processing matrix, full manifest row matrix, manifest content-script matrix, platform capability matrix, priority platform answer matrix, plus YouTube, TikTok, TikTok standalone app connector, Twitch, Kick, Rumble, Facebook, Instagram, Discord, generic/custom, static/manual/helper source, WebSocket/API source-page, communication/sensitive source, embedded chat widget source, live-commerce source, webinar/event source, creator/live-cam source, popout/chat-only source, event/community source, independent live platform source, video/broadcast platform source, community/membership web-app source, regional/emerging platform source, and special-case platform/helper source passes started/complete. - `09-api-and-integrations/index.md`: WebSocket/HTTP API, TTS, AI, OBS, StreamDeck/Companion, Event Flow, Streamer.bot, and API command validation heavy passes started. - `10-troubleshooting/index.md`: diagnostic decision tree, quick triage, extension capture, OBS overlay, desktop app, auth, settings/backup, and support-mined platform known-issue passes started/complete. - `11-support-kb/index.md`: support section map, first-answer router, triage evidence checklist, and privacy/source-priority rules. diff --git a/docs/agents/AGENT.md b/docs/agents/AGENT.md index 1f41f9e8f..b9b6d510a 100644 --- a/docs/agents/AGENT.md +++ b/docs/agents/AGENT.md @@ -85,6 +85,7 @@ For support-style answers: - `docs/agents/11-support-kb/support-macro-routing.md`: SSN-filtered support macros from curated support playbooks for safe intake, common short replies, and escalation routing. - `docs/agents/11-support-kb/common-question-coverage-map.md`: objective-level map of common question families to current docs. - `docs/agents/11-support-kb/common-misconceptions-and-boundaries.md`: common overclaims, stale-claim risks, and safer support wording. +- `docs/agents/08-platform-sources/priority-platform-answer-matrix.md`: safe phrasing and first checks for high-volume platform capability, rich-event, send-back, and app/extension platform questions. - `docs/agents/13-reference/public-claims-boundary-matrix.md`: boundaries for broad public claims such as 100+/120+ sites, two-way chat, no API keys, free/open-source, AI/TTS, app behavior, plugins/customization, services, and support promises. - `docs/agents/11-support-kb/support-response-playbook.md`: ready-to-send response templates and follow-up prompts. - `docs/agents/11-support-kb/support-evidence-ledger.md`: support claim families, evidence status, and next validation targets. From b41f50032742f89d2464c30d539eb922a7f95517 Mon Sep 17 00:00:00 2001 From: steveseguin Date: Wed, 24 Jun 2026 08:10:34 -0400 Subject: [PATCH 22/30] docs(agents): add priority platform validation ledger --- docs/agents/01-extraction-checklist.md | 1 + docs/agents/02-resource-processing-ledger.md | 6 +- docs/agents/08-platform-sources/SITEMAP.md | 1 + docs/agents/08-platform-sources/index.md | 3 +- .../platform-capability-matrix.md | 3 +- .../priority-platform-answer-matrix.md | 2 + .../priority-platform-validation-ledger.md | 94 +++++++++++++++++++ .../common-question-coverage-map.md | 4 +- .../common-question-fast-path.md | 4 +- .../11-support-kb/question-intent-router.md | 5 +- .../11-support-kb/support-evidence-ledger.md | 4 +- .../14-validation-and-refresh-roadmap.md | 4 +- ...-objective-coverage-and-readiness-audit.md | 8 +- docs/agents/19-navigation-and-link-audit.md | 2 +- docs/agents/99-agent-index.md | 6 +- docs/agents/AGENT.md | 1 + 16 files changed, 125 insertions(+), 23 deletions(-) create mode 100644 docs/agents/08-platform-sources/priority-platform-validation-ledger.md diff --git a/docs/agents/01-extraction-checklist.md b/docs/agents/01-extraction-checklist.md index 59d9e3e33..72d697cb2 100644 --- a/docs/agents/01-extraction-checklist.md +++ b/docs/agents/01-extraction-checklist.md @@ -168,6 +168,7 @@ Add one entry per extraction pass. | 2026-06-24 | Codex | Support history refresh playbook | Heavy support-refresh workflow pass | `11-support-kb/support-history-refresh-playbook.md`, support indexes/ledger/audit updates | heavy-complete | Added a safe repeatable support-history refresh workflow with aggregate SQLite query pack, current seed counts from `knowledge.sqlite` and `stevesbot.sqlite`, latest QA export reference, raw archive gate, stale-claim decision tree, and required downstream doc updates. Counts are priority signals only, not runtime/product proof. | | 2026-06-24 | Codex | App, extension, and mode crosswalk | Heavy support-routing/reference pass | `13-reference/app-extension-mode-crosswalk.md`, support/reference indexes/checklist/ledger/audit updates | heavy-complete | Added first-stop routing for Chrome extension vs standalone app vs hosted pages, local pages, Lite, Firefox, WebSocket/API source pages, and custom sources. Includes safe answer rules, surface matrix, app-vs-extension decision matrix, common confusion points, troubleshooting routes, recommended answer shapes, and overclaim guardrails. Not runtime-tested. | | 2026-06-24 | Codex | Priority platform answer matrix | Heavy support-routing/platform pass | `08-platform-sources/priority-platform-answer-matrix.md`, platform/support indexes/checklist/ledger/audit updates | heavy-complete | Added safe support phrasing and first-check routing for YouTube, TikTok, Twitch, Kick, Rumble, Facebook, Instagram, and Discord. The pass source-grepped send-back, source-control, auth/token, and rich-event terms, but did not perform live platform, app, or OBS testing. | +| 2026-06-24 | Codex | Priority platform validation ledger | Heavy platform evidence-ledger pass | `08-platform-sources/priority-platform-validation-ledger.md`, platform/support indexes/checklist/ledger/audit updates | heavy-complete | Added per-platform evidence labels, claim ledger, minimum proof packs, and update rules for high-risk YouTube, TikTok, Twitch, Kick, Rumble, Facebook, Instagram, and Discord support claims. This is not runtime validation. | | 2026-06-24 | Codex | Scoreboard controlled browser validation | Runtime browser validation | `17-runtime-validation-evidence-log.md`, `07-overlays-and-pages/live-display-utilities.md`, `07-overlays-and-pages/page-capability-matrix.md`, checklist/ledger/audit/index updates | browser-validated-partial | Ran `node scripts/playwright-scoreboard-e2e.cjs`; result `PASS scoreboard e2e`. Validated local headless Chromium behavior for `scoreboard.html` preview-mode points snapshot rendering, `maxusers`, `minpoints`, layout/theme/title/subtitle, local `chatpoints`, `donationpoints`, `customtriggers`, compact layout, and `hidepoints`. Did not test OBS, hosted page, extension/app bridge, live source payloads, WebSocket/server modes, session/password/label routing, or persistence. | | 2026-06-24 | Codex | Reactions overlay controlled browser validation | Runtime browser validation | `17-runtime-validation-evidence-log.md`, `07-overlays-and-pages/live-display-utilities.md`, `07-overlays-and-pages/page-capability-matrix.md`, checklist/ledger/audit/index updates | browser-validated-partial | Ran `node scripts/playwright-reactions-overlay-e2e.cjs`; result `Reactions overlay test passed with 12 blocked external request(s).` Validated controlled local headless Chromium behavior for popup-generated reactions URL parameters, `reactions.html` option parsing, synthetic VDO bridge liked payloads, direct reaction/liked payload rendering, inline image scaling, fake server-mode joins, and controlled TikTok-like target routing. Did not test OBS, hosted page, real extension runtime, real VDO bridge, real relay delivery, live TikTok/platform behavior, standalone app, or long-running persistence. | | 2026-06-24 | Codex | Multi-alerts controlled browser validation attempt | Runtime browser validation attempt | `17-runtime-validation-evidence-log.md`, `07-overlays-and-pages/multi-alerts.md`, `07-overlays-and-pages/page-capability-matrix.md`, checklist/ledger/audit/index updates | validation-failed | Ran `node scripts/playwright-multi-alerts-overlay-e2e.cjs`; result failed with `frame.waitForFunction: Timeout 30000ms exceeded` at `waitForPreviewFrame` while waiting for the preview iframe to expose `window.__multiAlertsOverlay.getSettings`. Do not promote multi-alert render, queue, filter, audio, or server-mode behavior to browser-validated from this run. | diff --git a/docs/agents/02-resource-processing-ledger.md b/docs/agents/02-resource-processing-ledger.md index 4aab5fc4c..e5359757a 100644 --- a/docs/agents/02-resource-processing-ledger.md +++ b/docs/agents/02-resource-processing-ledger.md @@ -32,7 +32,7 @@ Use this file to answer: "Has this resource been processed already, and how deep | Resource Area | Current Depth | Main Output Docs | Remaining Need | | --- | --- | --- | --- | | Overall objective coverage/readiness | heavy audit plus narrow runtime and focused validation evidence | `15-objective-coverage-and-readiness-audit.md`, `99-agent-index.md`, `14-validation-and-refresh-roadmap.md`, `16-runtime-validation-playbooks.md`, `17-runtime-validation-evidence-log.md`, `18-focused-validation-evidence-log.md` | Keep coverage current after new passes; do not mark the whole docs objective complete until runtime-tested claims and proof gaps are resolved. Use the runtime playbooks to record evidence before promoting claims. | -| Agent documentation navigation | quick/focused docs audit plus static viewer/sitemaps | `docs/index.html`, `docs/agents/SITEMAP.md`, section `docs/agents/*/SITEMAP.md` files, `19-navigation-and-link-audit.md`, `99-agent-index.md`, `AGENT.md`, section indexes | Static client-side Markdown viewer added at `docs/index.html`; root and per-section sitemap Markdown files added under `docs/agents`. Current focused audit covers 162 Markdown files with zero unreferenced non-template pages, zero broken exact agent-doc Markdown refs, and zero ambiguous bare section-index filenames. Refresh after sitemap changes and large doc-growth. | +| Agent documentation navigation | quick/focused docs audit plus static viewer/sitemaps | `docs/index.html`, `docs/agents/SITEMAP.md`, section `docs/agents/*/SITEMAP.md` files, `19-navigation-and-link-audit.md`, `99-agent-index.md`, `AGENT.md`, section indexes | Static client-side Markdown viewer added at `docs/index.html`; root and per-section sitemap Markdown files added under `docs/agents`. Current focused audit covers 163 Markdown files with zero unreferenced non-template pages, zero broken exact agent-doc Markdown refs, and zero ambiguous bare section-index filenames. Refresh after sitemap changes and large doc-growth. | | Runtime validation workflow | heavy planning plus evidence log | `14-validation-and-refresh-roadmap.md`, `16-runtime-validation-playbooks.md`, `17-runtime-validation-evidence-log.md`, `12-development/testing-and-validation.md` | Continue executing playbooks and recording real runtime evidence before promoting commands, URL options, sources, app flows, OBS pages, integrations, provider behavior, or support claims to tested. | | Existing test and validation assets | heavy inventory/routing plus focused config/metadata/Node/browser-fixture evidence | `12-development/test-asset-matrix.md`, `12-development/testing-and-validation.md`, `16-runtime-validation-playbooks.md`, `18-focused-validation-evidence-log.md` | Focused evidence now covers settings config JSON validation, generated settings/URL/public-site metadata checks with duplicate metadata findings, selected Event Flow internals, Twitch subgift normalization, AI prompt builder smoke behavior, profanity/moderation checks, local browser model registry checks, OpenCode Zen fallback checks, Kokoro and Kitten static TTS asset wiring, Transformers remote-host defaults, RAG fixture E2E/benchmark behavior, plus a failing Piper asset expectation. Keep the matrix current when npm aliases, Node tests, browser fixtures, shell validators, metadata checkers, or Playwright scripts change; run focused assets before using them as evidence. | | Product overview and install surfaces | heavy | `01-product-map.md`, `02-installation-and-surfaces.md`, `13-reference/app-extension-mode-crosswalk.md`, `13-reference/install-update-version-guide.md`, `13-reference/public-claims-boundary-matrix.md` | Intense claim reconciliation only if publishing user-facing final docs; app auto-update and exact extension export/import behavior still need verification. | @@ -44,7 +44,7 @@ Use this file to answer: "Has this resource been processed already, and how deep | URL/page routing and parameters | heavy plus source trace/inventory/crosswalk and focused generated metadata validation | `13-reference/control-surface-crosswalk.md`, `13-reference/workflow-setup-decision-tree.md`, `13-reference/preflight-checklists.md`, `13-reference/surface-url-cheatsheet.md`, `07-overlays-and-pages/page-capability-matrix.md`, `13-reference/url-parameters.md`, `13-reference/url-parameter-index.md`, `13-reference/url-option-examples.md`, `13-reference/url-parameter-source-trace.md`, `13-reference/root-page-url-parameter-matrix.md`, `13-reference/subpage-url-parameter-matrix.md` | `shared/config/urlParameters.js` focused metadata validation confirmed 255 generated URL parameter items, 23 sections, 2 groups, 302 lookup entries, and no missing required URL parameter fields. Findings remain for duplicate `password` aliases and normalized `strokecolor` aliases. Remaining needs: runtime validation of page-specific support outside the generated `dock.html` index, exact page/channel validation, theme/game/source-page parameter behavior, and browser/OBS validation of example behavior before final publication. | | Terminology/glossary | heavy | `13-reference/glossary.md` | UI-label and support-transcript synonym pass. | | Public supported sites and source files | heavy inventory/status plus public implementation map and focused public-card metadata validation | `08-platform-sources/source-inventory.md`, `supported-sites-lookup.md`, `public-site-support-status.md`, `public-site-implementation-map.md`, `source-file-processing-matrix.md`, `manifest-content-scripts.md`, `manifest-row-matrix.md` | `docs/js/sites.js` focused metadata validation confirmed 139 public site cards and no missing required fields, with a duplicate normalized `On24`/`ON24` card finding. Remaining needs: runtime health validation, duplicate/stale-card reconciliation, and quick notes for newly added files. | -| High-volume platform pages and capability routing | heavy plus focused Twitch provider evidence | YouTube, TikTok, Twitch, Kick, Rumble, Facebook, Instagram, Discord docs, `08-platform-sources/priority-platform-answer-matrix.md`, `08-platform-sources/platform-capability-matrix.md`, `18-focused-validation-evidence-log.md` | Priority support phrasing now has a dedicated matrix. Twitch subgift provider normalization has focused Node-test evidence only. Remaining needs: intense parser/event/auth/send-chat/app-parity validation and live platform checks. | +| High-volume platform pages and capability routing | heavy plus focused Twitch provider evidence | YouTube, TikTok, Twitch, Kick, Rumble, Facebook, Instagram, Discord docs, `08-platform-sources/priority-platform-answer-matrix.md`, `08-platform-sources/priority-platform-validation-ledger.md`, `08-platform-sources/platform-capability-matrix.md`, `18-focused-validation-evidence-log.md` | Priority support phrasing now has a dedicated matrix and evidence ledger. Twitch subgift provider normalization has focused Node-test evidence only. Remaining needs: intense parser/event/auth/send-chat/app-parity validation and live platform checks. | | Other platform sources | grouped quick/heavy passes | `02-resource-manifest.md`, `08-platform-sources/source-inventory.md`, `08-platform-sources/manual-static-and-helper-sources.md`, `08-platform-sources/websocket-source-pages.md`, `08-platform-sources/communication-and-sensitive-sources.md`, `08-platform-sources/embedded-chat-widget-sources.md`, `08-platform-sources/live-commerce-sources.md`, `08-platform-sources/webinar-and-event-sources.md`, `08-platform-sources/creator-live-cam-sources.md`, `08-platform-sources/popout-chat-only-sources.md`, `08-platform-sources/event-and-community-sources.md`, `08-platform-sources/independent-live-platform-sources.md`, `08-platform-sources/video-broadcast-platform-sources.md`, `08-platform-sources/community-membership-webapp-sources.md`, `08-platform-sources/regional-and-emerging-platform-sources.md`, `08-platform-sources/special-case-platform-and-helper-sources.md` | Live/browser validation and intense passes for fragile/high-risk platforms. | | Overlays and tool pages | heavy plus file-level ledger plus narrow browser validation evidence | `07-overlays-and-pages/*`, especially `page-capability-matrix.md`, `page-processing-matrix.md`, `diagnostic-helper-pages.md`, `game-pages.md`, `theme-pages.md`, and `17-runtime-validation-evidence-log.md` | `scoreboard.html` has controlled local browser validation for preview/local scoring only. `reactions.html` has controlled local browser validation for popup URL parsing, synthetic bridge/payload rendering, fake server-mode joins, and controlled TikTok-like target routing only. `multi-alerts.html` has a failed validation attempt waiting for the preview iframe overlay API. Remaining needs: per-page command handlers, storage, OBS behavior, channel/label behavior, controlled payload samples for other pages, game/theme rendering validation, import/export validation, replay validation, and broader test coverage. | | API and integrations | heavy plus source trace/crosswalk plus focused examples consistency check | `09-api-and-integrations/*`, `13-reference/control-surface-crosswalk.md`, `13-reference/action-command-index.md`, `13-reference/command-action-source-trace.md`, `13-reference/api-command-validation-matrix.md`, `13-reference/api-command-examples.md`, `18-focused-validation-evidence-log.md` | Static examples extraction found 29 action examples and, after docs updates, zero missing entries across action index, validation matrix, and source trace; `content4`/numbered channel caveats were added to the matrix and trace. Remaining needs: runtime command validation, callback/label/channel validation, and integration edge cases. | @@ -135,7 +135,7 @@ These resources have been mined enough to support heavy agent docs, but not enou | Event/community sources | `sources/arenasocial.js`, `buzzit.js`, `cime.js`, `gala.js`, `linkedin.js`, `livepush.js`, `megaphonetv.js`, `quickchannel.js`, `slido.js`, `tradingview.js` | `08-platform-sources/event-and-community-sources.md` | Live validation for Slido question rows, CI.ME donation/viewer data, Arena Social viewer counts, LivePush relayed source types, LinkedIn path gating, and MegaphoneTV source identity. | | Regional/emerging platform sources | `sources/bilibili.js`, `bilibilicom.js`, `favorited.js`, `kwai.js`, `pilled.js`, `portal.js`, `pumpfun.js`, `retake.js`, `rooter.js`, `shareplay.js`, `soulbound.js`, `streamplace.js`, `substack.js`, `tikfinity.js`, `uscreen.js`, `vklive.js`, `xeenon.js` | `08-platform-sources/regional-and-emerging-platform-sources.md` | Live validation for Bilibili URL variants, SharePlay shoutout/Blitz cards, Tikfinity feed payloads, Stream.place relayed rows, Substack live URL routing, Pump.fun/Retake tips, SoulBound manifest routing, and inactive viewer helpers. | | Special-case platform/helper sources | `sources/joystick.js`, `velora.js`, `vercel.js`, `verticalpixelzone.js`, `vpzone.js`, `x.js`, `youtube_comments.js`, `youtube_static.js` | `08-platform-sources/special-case-platform-and-helper-sources.md` | Live validation for Joystick/Velora/VPZone mode split, Vertical Pixel Zone selectors/source identity, X live URL variants, Vercel demo session sharing, and top-level YouTube helper load status. | -| Cross-platform capability routing | Platform docs, source inventory, manifest matrices, reference pages | `08-platform-sources/platform-capability-matrix.md`, `08-platform-sources/priority-platform-answer-matrix.md` | Send-chat, moderation, event-family, app-parity, and exact payload validation. | +| Cross-platform capability routing | Platform docs, source inventory, manifest matrices, reference pages | `08-platform-sources/platform-capability-matrix.md`, `08-platform-sources/priority-platform-answer-matrix.md`, `08-platform-sources/priority-platform-validation-ledger.md` | Send-chat, moderation, event-family, app-parity, and exact payload validation. | ### Remaining Platform Source Routing diff --git a/docs/agents/08-platform-sources/SITEMAP.md b/docs/agents/08-platform-sources/SITEMAP.md index 792da05d2..287602a11 100644 --- a/docs/agents/08-platform-sources/SITEMAP.md +++ b/docs/agents/08-platform-sources/SITEMAP.md @@ -27,6 +27,7 @@ Use this file to navigate this folder without scanning the filesystem. - [Manual, Static, And Helper Sources](../08-platform-sources/manual-static-and-helper-sources.md) - Use this page when a file in sources/static/, sources/inject/, or a helper-like sources/*.js row appears in the source matrix and the question is "is this a normal chat source?" - [Platform Capability Matrix](../08-platform-sources/platform-capability-matrix.md) - Use this page when an agent needs to answer "does SSN support this platform feature?" quickly. This is a routing matrix, not the final line-level source of truth. Before making a public or support-critical promise, check the linked platform doc and the current source. - [Priority Platform Answer Matrix](../08-platform-sources/priority-platform-answer-matrix.md) - Use this page for safe support phrasing and first checks for YouTube, TikTok, Twitch, Kick, Rumble, Facebook, Instagram, and Discord. +- [Priority Platform Validation Ledger](../08-platform-sources/priority-platform-validation-ledger.md) - Use this page to decide what evidence exists and what proof is still needed before making strong priority-platform claims. - [Popout And Chat-Only Sources](../08-platform-sources/popout-chat-only-sources.md) - Use this page for smaller supported platforms where the required setup is a popout, chat-only, or platform-specific chat URL. These are rendered DOM chat captures unless noted otherwise. - [Public Site Implementation Map](../08-platform-sources/public-site-implementation-map.md) - Use this page when a user asks whether a listed site is supported and the answer needs the current source route, manifest row, or grouped platform doc. - [Public Site Support Status](../08-platform-sources/public-site-support-status.md) - Use this page to decide how strong an answer can be when a user asks whether a site is supported. This page does not replace the full site list in supported-sites-lookup.md; it explains what a public listing means and what still needs source verification. diff --git a/docs/agents/08-platform-sources/index.md b/docs/agents/08-platform-sources/index.md index b752ccd01..eb51abe9c 100644 --- a/docs/agents/08-platform-sources/index.md +++ b/docs/agents/08-platform-sources/index.md @@ -6,7 +6,7 @@ Status: framework plus heavy passes for source inventory, supported-site lookup, This section tracks platform-specific source capture behavior. -For support-facing high-volume platform questions, start with `priority-platform-answer-matrix.md` before making exact claims about rich events, send-back, app parity, or mode-specific behavior. +For support-facing high-volume platform questions, start with `priority-platform-answer-matrix.md` before making exact claims about rich events, send-back, app parity, or mode-specific behavior. Use `priority-platform-validation-ledger.md` to check the proof state behind those short answers. ## High-Priority Pages @@ -20,6 +20,7 @@ For support-facing high-volume platform questions, start with `priority-platform - `manifest-row-matrix.md`: full 155-row content-script matrix with script, bucket, match count, flags, sample pattern, and public routing hints. - `platform-capability-matrix.md`: high-value platform and setup-type capability routing for chat capture, rich events, send-back, app differences, and support triage. - `priority-platform-answer-matrix.md`: safe support phrasing, first checks, and no-overclaim routing for YouTube, TikTok, Twitch, Kick, Rumble, Facebook, Instagram, and Discord. +- `priority-platform-validation-ledger.md`: evidence labels, per-platform claim ledger, and proof packs for high-risk priority-platform claims. - `youtube.md`: heavy extraction pass complete. - `tiktok.md`: heavy extraction pass complete. - `tiktok-standalone-app.md`: app-specific TikTok connector, signing, fallbacks, replies, event families, tests, and support triage. diff --git a/docs/agents/08-platform-sources/platform-capability-matrix.md b/docs/agents/08-platform-sources/platform-capability-matrix.md index a8e8b1b53..8a48ce102 100644 --- a/docs/agents/08-platform-sources/platform-capability-matrix.md +++ b/docs/agents/08-platform-sources/platform-capability-matrix.md @@ -4,7 +4,7 @@ Status: heavy synthesis pass from current agent platform docs, source inventory, Use this page when an agent needs to answer "does SSN support this platform feature?" quickly. This is a routing matrix, not the final line-level source of truth. Before making a public or support-critical promise, check the linked platform doc and the current source. -For support-facing short answers about YouTube, TikTok, Twitch, Kick, Rumble, Facebook, Instagram, and Discord, start with `priority-platform-answer-matrix.md` before using the broader matrix below. +For support-facing short answers about YouTube, TikTok, Twitch, Kick, Rumble, Facebook, Instagram, and Discord, start with `priority-platform-answer-matrix.md` before using the broader matrix below. Use `priority-platform-validation-ledger.md` when the question needs proof status or validation targets for those priority platforms. ## Source Anchors @@ -37,6 +37,7 @@ For support-facing short answers about YouTube, TikTok, Twitch, Kick, Rumble, Fa - `docs/agents/08-platform-sources/manifest-content-scripts.md` - `docs/agents/08-platform-sources/manifest-row-matrix.md` - `docs/agents/08-platform-sources/priority-platform-answer-matrix.md` +- `docs/agents/08-platform-sources/priority-platform-validation-ledger.md` - `docs/agents/13-reference/feature-support-decision-matrix.md` - `docs/agents/13-reference/modes-and-capability-matrix.md` - `docs/event-reference.html` diff --git a/docs/agents/08-platform-sources/priority-platform-answer-matrix.md b/docs/agents/08-platform-sources/priority-platform-answer-matrix.md index ceaf8a5ec..e2e132142 100644 --- a/docs/agents/08-platform-sources/priority-platform-answer-matrix.md +++ b/docs/agents/08-platform-sources/priority-platform-answer-matrix.md @@ -21,6 +21,8 @@ This page sits between: - `../13-reference/app-extension-mode-crosswalk.md` for app-vs-extension caveats. - `../13-reference/public-claims-boundary-matrix.md` for broad public wording boundaries. +For proof status behind these short answers, use `priority-platform-validation-ledger.md`. + ## Source Scan Anchors This pass checked the current docs plus source terms in: diff --git a/docs/agents/08-platform-sources/priority-platform-validation-ledger.md b/docs/agents/08-platform-sources/priority-platform-validation-ledger.md new file mode 100644 index 000000000..80178bf01 --- /dev/null +++ b/docs/agents/08-platform-sources/priority-platform-validation-ledger.md @@ -0,0 +1,94 @@ +# Priority Platform Validation Ledger + +Status: heavy evidence-ledger pass on 2026-06-24. This page converts high-volume platform support claims into proof targets. It is not runtime validation and does not mark any platform feature as tested. + +## Purpose + +Use this page when a user or agent needs to know: + +- whether a priority platform claim is source-backed, support-derived, focused-tested, or runtime-tested, +- what evidence would be needed before saying a feature "works", +- which docs and source files to inspect before answering, +- which risky platform claims should stay cautious. + +For short support wording, use `priority-platform-answer-matrix.md`. For broader feature routing across all source families, use `platform-capability-matrix.md`. + +## Evidence Labels + +| Label | Meaning | +| --- | --- | +| `orientation` | A doc route or safe answer exists, but the exact behavior is not validated. | +| `source-backed` | Current source/docs were inspected enough for cautious guidance. Still verify exact code paths before public promises. | +| `focused-tested` | A deterministic test or static check supports a narrow claim, but not live runtime behavior. | +| `runtime-needed` | Browser, app, API, OBS, or live platform testing is required before saying the behavior is tested. | +| `stale-risk` | Third-party platform behavior, selectors, OAuth scopes, API policy, or support history could be out of date. | +| `do-not-promise` | Do not claim this currently works unless a later pass adds current source and runtime evidence. | + +## Current Platform Evidence Summary + +| Platform | Plain Chat Evidence | Rich Event Evidence | Send-Back Evidence | App Parity Evidence | Current Safe Status | +| --- | --- | --- | --- | --- | --- | +| YouTube | source-backed DOM and WebSocket/API docs | source-backed but mode-specific | source-backed routing only; runtime-needed | source-backed OAuth notes; runtime-needed | Answer setup and mode questions; verify write/moderation claims before promising. | +| TikTok | source-backed DOM and app connector docs | source-backed app/DOM event notes | source-backed app reply paths; runtime-needed | source-backed app connector notes; runtime-needed | Treat as volatile and mode-specific; app has broadest routing but not blanket parity. | +| Twitch | source-backed DOM and WebSocket/EventSub docs | source-backed plus focused subgift provider test | source-backed provider paths; runtime-needed | source-backed OAuth notes; runtime-needed | Split DOM chat from EventSub/provider features. | +| Kick | source-backed DOM and bridge docs | source-backed bridge event notes | source-backed bridge send paths; runtime-needed | source-backed OAuth/app notes; runtime-needed | Split popout chat from bridge/OAuth features. | +| Rumble | source-backed DOM and API bridge docs | source-backed API bridge notes | documented read-only bridge; do-not-promise send-back | app parity unknown | API bridge is structured and read-only; keep private API URL secret. | +| Facebook | source-backed DOM and Graph bridge docs | source-backed viewer/comment notes | do-not-promise without new source/runtime proof | app OAuth not deeply validated | Split managed Page API bridge from viewer DOM capture. | +| Instagram | source-backed DOM docs | limited/source-backed live/feed notes | do-not-promise | app parity unknown | Treat as visible DOM capture only. | +| Discord | source-backed web DOM docs | limited/source-backed message/media notes | do-not-promise | app parity unknown | Treat as web Discord DOM capture, not a bot/API integration. | + +## Claim Ledger + +| Platform | Claim Family | Current Evidence | Risk | Proof Needed Before Strong Claim | +| --- | --- | --- | --- | --- | +| YouTube | Normal live chat/popout capture works. | `youtube.md`, `sources/youtube.js`, manifest/source docs | DOM selectors and YouTube page state can change. | Browser validation with live/popout chat, dock receipt, session match, and reload/stale-chat behavior. | +| YouTube | WebSocket/Data API gives richer events. | `youtube.md`, `sources/websocket/youtube.js`, `providers/youtube/liveChat.js` | OAuth scopes, stream state, polling/streaming behavior, and API limits. | Controlled source-page run with OAuth or mocked provider, event samples, delete/ban/subscriber paths where allowed. | +| YouTube | Send/delete/ban/moderation works. | Source-control and event names appear in docs/source routes | High write-permission and role risk. | Line-level source-control trace plus runtime source-page test with safe account and explicit OAuth scopes. | +| TikTok | DOM Standard mode reads rendered live chat and social rows. | `tiktok.md`, `sources/tiktok.js` | TikTok DOM changes frequently; account/region differences. | Browser validation with live account, visible chat, gifts/social rows, duplicate behavior, and hidden/visible tab comparison. | +| TikTok | App connector supports richer modes and events. | `tiktok.md`, `tiktok-standalone-app.md`, `ssapp/tiktok/connection-manager.js` | Signers, WebSocket bootstrap, rate limits, fallback, and app UI mode names change. | Electron app e2e with Standard, WS Auto, Local Signer, Polling, fallback states, event samples, logs, and app version. | +| TikTok | Replies/send-back work. | App send paths exist in `connection-manager.js`; docs note `sessionid` and mode requirements | Auth/session/signature/rate-limit risk. | Real app send test from a signed-in account in supported modes, with failure logs and mode-specific result. | +| Twitch | DOM chat works for visible Twitch chat. | `twitch.md`, `sources/twitch.js` | Twitch DOM/class changes and sign-in state. | Browser validation with visible chat, badges/emotes/replies, dock receipt, and viewer-count gating. | +| Twitch | EventSub/provider captures follows, raids, rewards, subs, cheers, deletes, bans, ads. | `twitch.md`, `sources/websocket/twitch.js`, `providers/twitch/chatClient.js` | OAuth scopes, broadcaster/moderator role, EventSub subscription availability. | Runtime WebSocket/EventSub setup with scoped token, event samples or controlled fixtures, and permission-error notes. | +| Twitch | Gifted subscription normalization. | Focused Node test in `tests/twitch-chatClient-subgift.test.js` | Synthetic provider test only; no live EventSub/IRC proof. | Live or replayed provider event test plus downstream overlay/API delivery. | +| Twitch | Send chat works. | `providers/twitch/chatClient.js` and `sources/websocket/twitch.js` have send-message paths | Requires connected tmi.js client, OAuth, target channel, and account permissions. | Runtime send test with safe channel and clear failure behavior when disconnected/unauthorized. | +| Kick | Popout chat capture works. | `kick.md`, `sources/kick.js`, `sources/kick_new.js` | Current manifest/runtime loading relationship still needs intense validation. | Browser validation on current popout URL, old chatroom redirect, viewer count, delete payloads, and source-file load confirmation. | +| Kick | Bridge handles rewards, subs, follows, raids, tips, moderation, and send-back. | `kick.md`, `sources/websocket/kick.js`, `providers/kick/core.js` | OAuth token/scopes, bridge state, Pusher behavior, CAPTCHA/human verification. | Runtime bridge validation with signed-in account, reward event, chat send, reconnect/token-refresh, and app-vs-browser comparison. | +| Kick | App OAuth behaves like browser OAuth. | App OAuth docs/source notes exist | CAPTCHA, local/external auth, loopback ports, and Electron window behavior differ. | Electron app OAuth e2e for local and external flows, including failure/CAPTCHA handling. | +| Rumble | Normal DOM capture reads visible chat/rants/raids. | `rumble.md`, `sources/rumble.js` | DOM markup and source-tab state. | Browser validation with normal Rumble page, visible chat/rant/raid samples where available. | +| Rumble | Live Stream API bridge handles structured events. | `rumble.md`, `sources/websocket/rumble.js` | Private API URL, stream state, SSE/polling fallback, replay/dedupe. | Runtime API bridge validation with private test URL, chat/rant/follow/sub/viewer/status samples, and replay off/on comparison. | +| Rumble | API bridge sends chat. | Source logs state read-only behavior for `SEND_MESSAGE` attempts | Do-not-promise. | Only change if source changes and runtime proves send behavior. | +| Facebook | DOM capture reads visible live comments/Stars rows. | `facebook.md`, `sources/facebook.js` | Viewer/admin context, Facebook layout churn. | Browser validation in viewer and page-owner contexts with visible comments and Stars where available. | +| Facebook | Managed Page Graph bridge reads comments/viewers. | `facebook.md`, `sources/websocket/facebook.js` | Page role, token permissions, live video ID, Graph API changes. | Runtime bridge validation with managed Page token, live video, comments, viewer count, token-expiry behavior, and permission errors. | +| Facebook | Send-back or Stars parity is supported. | Not proven by current docs | High API/write and payload risk. | Current source path plus live Graph/API validation before any claim. | +| Instagram | Live DOM capture reads visible live rows. | `instagram.md`, `sources/instagram.js`, `sources/instagramlive.js` | DOM placeholders, login state, page layout, source-file routing. | Browser validation with live page, new chat rows, joined-event setting, and downstream source type check. | +| Instagram | Feed/post/comment capture works. | `instagram.md`, `sources/instagram.js` | Infinite scroll, expanded comment state, media/lazy loading. | Browser validation with feed/post comments, expanded replies, media, duplicate avoidance. | +| Instagram | Send-back/API-style integration works. | Not proven by current docs | Do-not-promise. | New source/API bridge plus runtime evidence would be required. | +| Discord | Web Discord DOM capture works. | `discord.md`, `sources/discord.js` | Discord DOM changes, source toggle, channel filter, login state. | Browser validation on `/channels/` URL, new message, attachment/media, custom channel filter, membership color behavior. | +| Discord | Discord bot/API, role/moderation, or send-back works. | Not proven by current docs | Do-not-promise. | Dedicated bot/API integration and runtime evidence would be required. | + +## Minimum Proof Pack By Claim Type + +| Claim Type | Minimum Evidence | +| --- | --- | +| Plain chat capture works | Exact source/mode, real or controlled new message, dock receipt, same session proof, browser/app surface, and "what was not tested." | +| Rich event works | Event source/mode, sample payload, downstream receipt, event name/fields, account role/scope, and whether DOM/API/app mode differs. | +| Send-back works | Exact source-control/send path, logged-in account, target channel, OAuth scopes/role, safe sent message, error behavior, and platform policy caveat. | +| Viewer count works | Setting/source mode, stream live state, payload sample, polling interval/source, and missing/zero behavior. | +| App parity exists | Same platform and mode tested in extension and app, with app version, source-window state, session partition, auth path, and observed differences. | +| OBS overlay receives platform event | Source event reaches dock/API first, overlay URL/session/label is correct, OBS/browser source renders it, and refresh/persistence behavior is noted. | + +## What To Update After Validation + +When a platform claim is validated: + +1. Add a dated entry to `../17-runtime-validation-evidence-log.md` for runtime proof or `../18-focused-validation-evidence-log.md` for focused non-runtime proof. +2. Update the relevant platform doc. +3. Update `priority-platform-answer-matrix.md` if safe support wording changes. +4. Update `platform-capability-matrix.md` if capability routing changes. +5. Update `../11-support-kb/support-evidence-ledger.md` if a support claim is promoted, narrowed, or rejected. +6. Add a pass row to `../01-extraction-checklist.md`. +7. Update `../02-resource-processing-ledger.md` and `../15-objective-coverage-and-readiness-audit.md` if evidence strength changes. + +## Current Non-Completion Boundary + +This ledger makes the validation gaps explicit, but it does not close them. The priority platform docs are useful for cautious answers, not final tested claims. Do not mark platform send-back, moderation, app parity, or live rich-event behavior as `runtime-tested` until the proof pack above exists. diff --git a/docs/agents/11-support-kb/common-question-coverage-map.md b/docs/agents/11-support-kb/common-question-coverage-map.md index e7232b634..9b3dcb65e 100644 --- a/docs/agents/11-support-kb/common-question-coverage-map.md +++ b/docs/agents/11-support-kb/common-question-coverage-map.md @@ -48,8 +48,8 @@ For plain-language user wording and first-route selection, use `question-intent- | Why does the supported-site list not prove every feature works? | covered-heavy | `08-platform-sources/public-site-support-status.md` | `08-platform-sources/platform-capability-matrix.md` | | Which source file handles a public site card? | covered-heavy | `08-platform-sources/public-site-implementation-map.md` | `source-file-processing-matrix.md`, `manifest-content-scripts.md`, `manifest-row-matrix.md` | | What is the difference between standard DOM capture, popout capture, static helper, injected helper, and WebSocket/API source page? | covered-heavy | `13-reference/modes-and-capability-matrix.md` | `08-platform-sources/manual-static-and-helper-sources.md`, `websocket-source-pages.md` | -| Does a platform support gifts, tips, raids, rewards, follows, viewer counts, or moderation events? | mixed, needs-intense | `08-platform-sources/priority-platform-answer-matrix.md` | `08-platform-sources/platform-capability-matrix.md`, exact platform doc, and current source | -| Can SSN send chat back to a platform? | mixed, needs-intense | `08-platform-sources/priority-platform-answer-matrix.md` | `platform-capability-matrix.md`, `websocket-source-pages.md`, exact platform source | +| Does a platform support gifts, tips, raids, rewards, follows, viewer counts, or moderation events? | mixed, needs-intense | `08-platform-sources/priority-platform-answer-matrix.md` | `08-platform-sources/priority-platform-validation-ledger.md`, `08-platform-sources/platform-capability-matrix.md`, exact platform doc, and current source | +| Can SSN send chat back to a platform? | mixed, needs-intense | `08-platform-sources/priority-platform-answer-matrix.md` | `08-platform-sources/priority-platform-validation-ledger.md`, `platform-capability-matrix.md`, `websocket-source-pages.md`, exact platform source | | Can SSN capture private chats, meetings, or assistant pages? | covered-heavy, needs-live-validation | `08-platform-sources/communication-and-sensitive-sources.md` | privacy/toggle/source checks | | Are helper files real chat parsers? | covered-heavy | `08-platform-sources/manual-static-and-helper-sources.md` | `08-platform-sources/special-case-platform-and-helper-sources.md` | | How do Joystick, Velora, VPZone, X, Vertical Pixel Zone, Vercel helper, or top-level YouTube helper copies fit? | covered-heavy, needs-live-validation | `08-platform-sources/special-case-platform-and-helper-sources.md` | exact source file and manifest row | diff --git a/docs/agents/11-support-kb/common-question-fast-path.md b/docs/agents/11-support-kb/common-question-fast-path.md index cdd207aeb..00b1865b0 100644 --- a/docs/agents/11-support-kb/common-question-fast-path.md +++ b/docs/agents/11-support-kb/common-question-fast-path.md @@ -38,8 +38,8 @@ This page is intentionally compact. It points to the deeper docs rather than res | "How many sites are supported?" | The public site list is large and current docs route 139 public cards from the latest extraction, but focused metadata validation found duplicate `On24`/`ON24` cards and exact site health/feature support still need source/mode checks. | `08-platform-sources/supported-sites-lookup.md`, `08-platform-sources/public-site-support-status.md`, `13-reference/public-claims-boundary-matrix.md` | "Every listed site fully works right now." | | "Is this site supported?" | Check the public card, setup type, implementation map, and source/mode docs before answering. | `08-platform-sources/supported-sites-lookup.md`, `08-platform-sources/public-site-implementation-map.md`, exact platform doc | "Supported means all features work." | | "Why is a listed site broken?" | A public listing is a setup route, not runtime proof; confirm exact URL, mode, source visibility, manifest/source load, and recent platform changes. | `08-platform-sources/public-site-support-status.md`, exact source file | "The list proves it cannot be broken." | -| "Can it send chat back?" | Maybe, depending on platform, source mode, login/auth, permissions, and current implementation. | `08-platform-sources/priority-platform-answer-matrix.md`, `08-platform-sources/platform-capability-matrix.md`, `08-platform-sources/websocket-source-pages.md`, exact platform source | "Yes, because chat capture works." | -| "Does it support gifts, raids, rewards, follows, or viewer counts?" | Often platform/mode-specific; use priority/capability docs as orientation and source-check the exact event family. | `08-platform-sources/priority-platform-answer-matrix.md`, `08-platform-sources/platform-capability-matrix.md`, platform doc, Event Flow docs | "All supported sites expose rich events." | +| "Can it send chat back?" | Maybe, depending on platform, source mode, login/auth, permissions, and current implementation. | `08-platform-sources/priority-platform-answer-matrix.md`, `08-platform-sources/priority-platform-validation-ledger.md`, `08-platform-sources/platform-capability-matrix.md`, `08-platform-sources/websocket-source-pages.md`, exact platform source | "Yes, because chat capture works." | +| "Does it support gifts, raids, rewards, follows, or viewer counts?" | Often platform/mode-specific; use priority/capability docs as orientation and source-check the exact event family. | `08-platform-sources/priority-platform-answer-matrix.md`, `08-platform-sources/priority-platform-validation-ledger.md`, `08-platform-sources/platform-capability-matrix.md`, platform doc, Event Flow docs | "All supported sites expose rich events." | | "Should I use extension or app?" | Use the extension for normal browser/cookie workflows; use the app for managed source windows or some throttling/source-window workflows. | `13-reference/app-extension-mode-crosswalk.md`, `13-reference/modes-and-capability-matrix.md`, `04-standalone-app-source-windows.md` | "The app fixes every login or platform problem." | | "Does the app behave like Chrome?" | Some behavior is shared, but Electron windows, sessions, source injection, OAuth handlers, and embedded login can differ. | `13-reference/app-extension-mode-crosswalk.md`, `04-standalone-app-source-windows.md`, `10-troubleshooting/desktop-app-issues.md` | "App and extension are identical." | | "What page do I open?" | Pick by job: source page for capture/API setup, dock for control, featured/theme pages for OBS output, sampleapi for command testing. | `13-reference/surface-url-cheatsheet.md`, `13-reference/workflow-setup-decision-tree.md` | "Always open dock only." | diff --git a/docs/agents/11-support-kb/question-intent-router.md b/docs/agents/11-support-kb/question-intent-router.md index 22e0087c6..3628f226d 100644 --- a/docs/agents/11-support-kb/question-intent-router.md +++ b/docs/agents/11-support-kb/question-intent-router.md @@ -20,6 +20,7 @@ This page complements: - `../13-reference/control-surface-crosswalk.md` for command/setting/URL/mode/plugin disambiguation. - `../13-reference/customization-path-decision-matrix.md` for ambiguous plugin/customization/source requests. - `../08-platform-sources/priority-platform-answer-matrix.md` for safe high-volume platform phrasing before exact source validation. +- `../08-platform-sources/priority-platform-validation-ledger.md` for proof status and validation targets behind high-volume platform claims. - `../13-reference/index.md` for broad reference routing. Rule: do not stop at this page for fragile claims. If the answer depends on selectors, exact platform support, send-back, auth, settings persistence, app parity, command payloads, or runtime behavior, open the routed topic doc and current source before giving a final-grade answer. @@ -42,8 +43,8 @@ Rule: do not stop at this page for fragile claims. If the answer depends on sele | "Is this site supported?" | Public site lookup | `../08-platform-sources/supported-sites-lookup.md` | Setup type and support-strength notes, not just the public card name. | | "Which source file handles this site?" | Implementation lookup | `../08-platform-sources/public-site-implementation-map.md` | Manifest row/source-page/stale-risk notes. | | "Why is a listed site broken?" | Supported-site caveat | `../08-platform-sources/public-site-support-status.md` | Exact URL, mode, current source, platform layout changes. | -| "Does this platform support raids/rewards/gifts/follows?" | Rich event support | `../08-platform-sources/priority-platform-answer-matrix.md` | Exact platform doc, capability matrix, and mode-specific source before promising. | -| "Can SSN send chat back?" | Send-back support | `../08-platform-sources/priority-platform-answer-matrix.md` | Source mode, login/auth, permissions, send path, platform policy. | +| "Does this platform support raids/rewards/gifts/follows?" | Rich event support | `../08-platform-sources/priority-platform-answer-matrix.md` | `../08-platform-sources/priority-platform-validation-ledger.md`, exact platform doc, capability matrix, and mode-specific source before promising. | +| "Can SSN send chat back?" | Send-back support | `../08-platform-sources/priority-platform-answer-matrix.md` | `../08-platform-sources/priority-platform-validation-ledger.md`, source mode, login/auth, permissions, send path, platform policy. | | "This is a private chat/meeting/work app" | Sensitive source | `../08-platform-sources/communication-and-sensitive-sources.md` | Opt-in toggle, visible web panel, privacy redaction, no assumed send-back. | | "What source mode is this?" | Capture mode classification | `../13-reference/modes-and-capability-matrix.md` | DOM, popout, static/manual, injected helper, WebSocket/API source page, app window. | | "Which page should I open?" | Surface URL routing | `../13-reference/surface-url-cheatsheet.md` | Source page vs overlay page vs API test page vs diagnostic helper. | diff --git a/docs/agents/11-support-kb/support-evidence-ledger.md b/docs/agents/11-support-kb/support-evidence-ledger.md index 82aa76f2c..ed24900a3 100644 --- a/docs/agents/11-support-kb/support-evidence-ledger.md +++ b/docs/agents/11-support-kb/support-evidence-ledger.md @@ -30,7 +30,7 @@ Each row maps a common support claim family to the best current evidence, the do | Chat missing from the dock is usually capture/session/source-mode related. | mixed | `10-troubleshooting/quick-triage.md`, `10-troubleshooting/extension-not-capturing.md`, `support-answer-bank.md` | Source-check exact platform mode and URL shape before platform-specific answers. | | Dock works but OBS/overlay does not is usually session, URL, refresh, CSS, or display-state related. | mixed | `10-troubleshooting/obs-overlay-display.md`, `13-reference/surface-url-cheatsheet.md`, `support-answer-bank.md` | Validate common overlays in OBS/browser with controlled payloads. | | Some sites require popout/chat-only URLs; others work on normal rendered pages or source pages. | source-backed by source inventory plus focused public-card metadata finding, needs-live-validation | `08-platform-sources/public-site-support-status.md`, `supported-sites-lookup.md`, platform docs | Replace heuristic site/source matches with exact generated public-site-to-manifest-to-source mapping and reconcile duplicate `On24`/`ON24` public cards. | -| Platform support depends on mode and feature; "supported" does not mean all events/send-back/moderation work. | source-backed, high-risk exact claims | `08-platform-sources/platform-capability-matrix.md`, `13-reference/feature-support-decision-matrix.md`, `13-reference/public-claims-boundary-matrix.md`, `support-answer-bank.md` | Line-level validation for send-back, moderation, reward, gift, raid, and auth claims. | +| Platform support depends on mode and feature; "supported" does not mean all events/send-back/moderation work. | source-backed, high-risk exact claims | `08-platform-sources/priority-platform-validation-ledger.md`, `08-platform-sources/platform-capability-matrix.md`, `13-reference/feature-support-decision-matrix.md`, `13-reference/public-claims-boundary-matrix.md`, `support-answer-bank.md` | Use the priority platform ledger to split orientation, source-backed, focused-tested, runtime-needed, and do-not-promise claims before line-level or live validation. | | Communication, meeting, assistant, and membership sources are privacy-sensitive and should be opt-in or redacted in support. | source-backed plus support-policy derived | `08-platform-sources/communication-and-sensitive-sources.md`, `11-support-kb/index.md` | Verify current toggle behavior and any send-back/background paths. | | WebSocket/API source pages are setup/control pages, not normal OBS overlays. | source-backed | `08-platform-sources/websocket-source-pages.md`, `13-reference/surface-url-cheatsheet.md`, `support-answer-bank.md` | Line-level validation for auth, reconnect, send-back, and app bridge behavior. | | Static/manual/helper source files are not always live chat parsers. | source-backed | `08-platform-sources/manual-static-and-helper-sources.md`, `special-case-platform-and-helper-sources.md`, `support-answer-bank.md` | Live/browser validation for helper behavior and manifest load status. | @@ -62,5 +62,5 @@ Before moving a support claim into a final answer or polished doc: - Add source-file references for the highest-volume support claims after intense passes. - Add one row per high-frequency SQLite topic after deeper query passes. -- Split platform evidence rows into per-platform ledgers when a platform gets a full intense validation pass. +- Execute or refine `08-platform-sources/priority-platform-validation-ledger.md` when priority platform claims get focused or runtime evidence. - Add a "tested in app/browser/OBS" column only after real e2e validation exists. diff --git a/docs/agents/14-validation-and-refresh-roadmap.md b/docs/agents/14-validation-and-refresh-roadmap.md index 177d64589..7d810041c 100644 --- a/docs/agents/14-validation-and-refresh-roadmap.md +++ b/docs/agents/14-validation-and-refresh-roadmap.md @@ -27,7 +27,7 @@ Current overlay runtime notes: `scoreboard.html` and `reactions.html` have narro Current focused validation notes: Event Flow custom JS, compare-property, template/counter, OBS system trigger, and play-media duration Node tests have focused evidence in `18-focused-validation-evidence-log.md`. Twitch subgift provider normalization, AI prompt builder smoke behavior, profanity/moderation static checks, local browser model registry checks, OpenCode Zen fallback checks, Kokoro asset wiring, Kitten TTS asset wiring, Transformers local defaults, RAG browser-fixture/benchmark behavior, settings config JSON validation, generated settings/URL/public-site metadata validation, and API command examples documentation consistency also have focused evidence there. Piper asset wiring has a failed focused test on an expected fallback remote-base string. The generated metadata check completed with duplicate URL alias findings for `password` and normalized `strokecolor`, plus duplicate public `On24`/`ON24` cards. The API examples consistency check found 29 extracted action examples and, after docs updates, zero missing entries across action index, validation matrix, and source trace, but it does not validate command behavior. These results do not validate Event Flow UI, Flow Actions overlay, OBS, app, extension, live platform behavior, browser audio, model runtime, real RAG uploads, live moderation quality, live LLM generation, generated overlay quality, provider calls, provider availability/pricing, popup/settings UI, generated docs UI, page-specific URL parsing, public supported-sites UI, API relay behavior, action callbacks, target labels, numbered content channels, or external integration behavior. -Current docs-navigation note: `19-navigation-and-link-audit.md` records a focused agent-doc navigation audit. The latest result found 162 Markdown files, zero unreferenced non-template pages, zero broken exact agent-doc Markdown references, and zero ambiguous bare section-index filenames. Re-run it after large documentation-growth, rename, or section-index changes. +Current docs-navigation note: `19-navigation-and-link-audit.md` records a focused agent-doc navigation audit. The latest result found 163 Markdown files, zero unreferenced non-template pages, zero broken exact agent-doc Markdown references, and zero ambiguous bare section-index filenames. Re-run it after large documentation-growth, rename, or section-index changes. ## Priority Queue @@ -39,7 +39,7 @@ Current docs-navigation note: `19-navigation-and-link-audit.md` records a focuse | P0 | Standalone app source windows and auth | `04-standalone-app-source-windows.md`, `04-standalone-app-architecture.md`, `10-troubleshooting/desktop-app-issues.md`, `10-troubleshooting/auth-and-sign-in.md` | `ssapp/main.js`, `preload.js`, `renderer.js`, `state.js`, OAuth handlers, TikTok app files | Electron e2e notes, source-window lifecycle trace, session partition behavior, auth callback limits, app-vs-extension parity fixes. | | P0 | Support claim promotion | `13-reference/public-claims-boundary-matrix.md`, `11-support-kb/support-evidence-ledger.md`, `11-support-kb/common-question-coverage-map.md`, `11-support-kb/common-misconceptions-and-boundaries.md`, `11-support-kb/unresolved-or-stale-claims.md` | Current code/docs plus curated `stevesbot` support files | Move claims from broad public/historical/anecdotal to source-backed/current, or mark stale/unknown. | | P1 | Public supported-site health map | `08-platform-sources/supported-sites-lookup.md`, `08-platform-sources/public-site-support-status.md`, `08-platform-sources/public-site-implementation-map.md`, `08-platform-sources/manifest-row-matrix.md`, `08-platform-sources/source-file-processing-matrix.md` | `docs/js/sites.js`, `manifest.json`, `sources/*`, real platform pages where possible | Runtime health/status validation for the public site map, duplicate `On24`/`ON24` and other stale-card reconciliation, and support-strength updates. | -| P1 | High-volume platform behavior | YouTube, TikTok, Twitch, Kick, Rumble, Facebook, Instagram, Discord docs and `08-platform-sources/platform-capability-matrix.md` | Platform source files, provider cores, app handlers, real/live test accounts where possible | Exact rich-event, send-back, auth, viewer count, app parity, and known-fragility matrix. | +| P1 | High-volume platform behavior | YouTube, TikTok, Twitch, Kick, Rumble, Facebook, Instagram, Discord docs, `08-platform-sources/priority-platform-validation-ledger.md`, and `08-platform-sources/platform-capability-matrix.md` | Platform source files, provider cores, app handlers, real/live test accounts where possible | Exact rich-event, send-back, auth, viewer count, app parity, and known-fragility matrix. | | P1 | Dock, featured, and core overlays | `07-overlays-and-pages/dock.md`, `featured.md`, `multi-alerts.md`, `page-capability-matrix.md` | Root overlay HTML/JS, background handlers, WebSocket bridge, OBS/browser sources | Controlled payload validation, OBS behavior, command target labels, persistence and audio notes. | | P1 | Event Flow and Streamer.bot | `09-api-and-integrations/event-flow-editor.md`, `streamerbot.md`, `13-reference/action-command-index.md` | `actions/*`, Event Flow tests/docs, Streamer.bot setup page, bridge commands | Trigger/action behavior, storage/import/export rules, integration failure notes. | | P1 | Customization/plugin paths | `13-reference/customization-path-decision-matrix.md`, `13-reference/customization-source-trace.md`, `customization-plugin-recipes.md`, `custom-plugins-and-extensions.md`, `07-overlays-and-pages/custom-overlays.md`, `12-development/adding-a-source.md` | `custom_sample.js`, `custom_actions.js`, `dock.html`, `featured.html`, `background.js`, `popup.js`, `sampleoverlay.html`, `sample_wss_source.html`, `api.md`, Event Flow custom code paths | Runtime-validated path examples, hosted/local/app caveats, uploaded custom user function behavior, payload samples, and safe sharing boundaries. | diff --git a/docs/agents/15-objective-coverage-and-readiness-audit.md b/docs/agents/15-objective-coverage-and-readiness-audit.md index de7dd923f..e5dee6978 100644 --- a/docs/agents/15-objective-coverage-and-readiness-audit.md +++ b/docs/agents/15-objective-coverage-and-readiness-audit.md @@ -37,7 +37,7 @@ Steve asked for comprehensive AI-focused documentation around: | --- | --- | --- | --- | | Agent workspace scope and rules | `AGENT.md`, `00-inventory-and-plan.md` | covered-heavy | Keep updated if write boundary or source priority changes. | | Resource inventory and extraction checklist | `02-resource-manifest.md`, `01-extraction-checklist.md`, `02-resource-processing-ledger.md` | covered-heavy | Continue adding pass rows after every new extraction/validation pass. | -| Agent-doc navigation and link hygiene | `docs/index.html`, `docs/agents/SITEMAP.md`, section `docs/agents/*/SITEMAP.md` files, `99-agent-index.md`, `AGENT.md`, `19-navigation-and-link-audit.md`, section indexes | covered-quick plus focused docs audit plus static viewer/sitemaps | Current audit covers 162 Markdown files with zero unreferenced non-template pages, zero broken exact agent-doc Markdown refs, and zero ambiguous bare section-index filenames. Browser smoke passed for default doc load, deep link load, section sitemap link traversal, raw link state, sidebar filter, and zero console errors. Re-run after major page additions, renames, or section index changes; current audit does not validate external/source links or all rendered anchors. | +| Agent-doc navigation and link hygiene | `docs/index.html`, `docs/agents/SITEMAP.md`, section `docs/agents/*/SITEMAP.md` files, `99-agent-index.md`, `AGENT.md`, `19-navigation-and-link-audit.md`, section indexes | covered-quick plus focused docs audit plus static viewer/sitemaps | Current audit covers 163 Markdown files with zero unreferenced non-template pages, zero broken exact agent-doc Markdown refs, and zero ambiguous bare section-index filenames. Browser smoke passed for default doc load, deep link load, section sitemap link traversal, raw link state, sidebar filter, and zero console errors. Re-run after major page additions, renames, or section index changes; current audit does not validate external/source links or all rendered anchors. | | Common question routing and evidence status | `11-support-kb/question-intent-router.md`, `11-support-kb/common-question-fast-path.md`, `11-support-kb/common-question-evidence-status.md`, `11-support-kb/common-question-test-set.md`, `11-support-kb/support-question-phrasebook.md`, `11-support-kb/common-question-coverage-map.md` | covered-heavy plus prompt benchmark | Add new paraphrased support wording after future QA exports and add runtime evidence only after actual validation. Use the test set to check common prompt routing and safe-answer behavior. | | Short support answers and response phrasing | `11-support-kb/support-answer-bank.md`, `support-response-playbook.md`, `support-macro-routing.md`, `support-intake-templates.md` | covered-heavy | Source-check fragile platform claims before sending final answers. | | Support-history evidence and stale-claim handling | `11-support-kb/mining-method.md`, `support-history-refresh-playbook.md`, `support-topic-frequency-index.md`, `historical-issues.md`, `support-evidence-ledger.md`, `unresolved-or-stale-claims.md`, `stevesbot-resource-inventory.md` | covered-heavy/frequency-pass plus repeatable refresh workflow | Promote or reject historical claims only after current source or runtime validation. Use the refresh playbook to rerun aggregate support-history counts without leaking raw support data. | @@ -47,7 +47,7 @@ Steve asked for comprehensive AI-focused documentation around: | App auth/sign-in issues | `10-troubleshooting/auth-and-sign-in.md`, `04-standalone-app-source-windows.md` | covered-heavy/source-backed | Validate OAuth callbacks, ports, external browser/profile behavior, and platform sign-in paths against current app runtime. | | Supported site list and setup type | `08-platform-sources/supported-sites-lookup.md`, `public-site-support-status.md`, `public-site-implementation-map.md`, `18-focused-validation-evidence-log.md` | covered-heavy/generated-source inventory plus focused metadata validation | Runtime health validation against real platform pages; reconcile stale/duplicate public cards, including duplicate `On24`/`ON24` metadata. | | Source file and manifest routing | `08-platform-sources/source-inventory.md`, `source-file-processing-matrix.md`, `manifest-content-scripts.md`, `manifest-row-matrix.md` | covered-heavy/generated-source inventory | Source-check newly added files and validate content-script behavior in browser/app. | -| Platform capability support | `08-platform-sources/priority-platform-answer-matrix.md`, `08-platform-sources/platform-capability-matrix.md`, individual platform docs | covered-heavy/orientation | Intense validation for send-back, moderation, gifts, rewards, raids, follows, viewer counts, auth, and app parity. | +| Platform capability support | `08-platform-sources/priority-platform-answer-matrix.md`, `08-platform-sources/priority-platform-validation-ledger.md`, `08-platform-sources/platform-capability-matrix.md`, individual platform docs | covered-heavy/orientation | Intense validation for send-back, moderation, gifts, rewards, raids, follows, viewer counts, auth, and app parity. | | Priority platforms | `youtube.md`, `tiktok.md`, `tiktok-standalone-app.md`, `twitch.md`, `kick.md`, `rumble.md`, `facebook.md`, `instagram.md`, `discord.md` | covered-heavy | Runtime and line-level validation for volatile auth/API/DOM/app-connector changes. | | Long-tail platform/source families | grouped `08-platform-sources/*.md` docs | covered-heavy/grouped | Browser/live validation for fragile DOM selectors and exact URL modes. | | Custom/generic sources | `08-platform-sources/generic-and-custom-sources.md`, `12-development/adding-a-source.md` | covered-heavy | Validate sample payloads and app/extension parity for new-source workflow. | @@ -120,7 +120,7 @@ The documentation objective should not be marked complete until current evidence 9. Runtime-tested claims have actual runtime evidence, not only static/source inspection. 10. Docs-only validation passes and no files outside the approved docs scope, `docs/index.html` plus `docs/agents`, were changed for the documentation work. -Items 1 through 8 are mostly covered. Item 6 now has focused docs-navigation audit support from `19-navigation-and-link-audit.md`, which found zero unreferenced non-template Markdown pages, zero broken exact agent-doc Markdown references, and zero ambiguous bare section-index filenames across 162 Markdown files. Items 9 and 10 must be rechecked at the end of every continuation. Item 9 remains the largest reason not to mark the full objective complete. +Items 1 through 8 are mostly covered. Item 6 now has focused docs-navigation audit support from `19-navigation-and-link-audit.md`, which found zero unreferenced non-template Markdown pages, zero broken exact agent-doc Markdown references, and zero ambiguous bare section-index filenames across 163 Markdown files. Items 9 and 10 must be rechecked at the end of every continuation. Item 9 remains the largest reason not to mark the full objective complete. Current runtime evidence is partial. As of 2026-06-24, `17-runtime-validation-evidence-log.md` records controlled local browser validation for `scoreboard.html` preview/local scoring behavior and `reactions.html` popup URL parsing, synthetic bridge/payload rendering, fake server-mode joins, and controlled TikTok-like target routing. It also records a failed `multi-alerts.html` validation attempt that timed out waiting for the preview iframe overlay API. This evidence does not validate OBS, hosted pages, the real extension/app bridge, live platform/source payloads, real WebSocket relay delivery, labels/password/session behavior outside the tested URLs, or long-running persistence. @@ -133,5 +133,5 @@ Focused non-runtime evidence is also partial. As of 2026-06-24, `18-focused-vali 3. Validate public supported-site health for stale-risk cards in `public-site-implementation-map.md`. 4. Validate standalone app source-window, OAuth, settings, backup/import/export, and TikTok connector/signing/reply workflows in a real app run. 5. Validate OBS/browser rendering for dock, featured, multi-alerts, themes, games, and diagnostic/helper pages. -6. Split high-risk platform support into source/runtime-validated mini ledgers for YouTube, TikTok, Twitch, Kick, Facebook, Instagram, Rumble, and Discord. +6. Execute the priority platform validation ledger with real source-line and runtime proof for YouTube, TikTok, Twitch, Kick, Facebook, Instagram, Rumble, and Discord. 7. Re-run support-history mining after new curated QA exports and update `support-question-phrasebook.md` and `support-topic-frequency-index.md`. diff --git a/docs/agents/19-navigation-and-link-audit.md b/docs/agents/19-navigation-and-link-audit.md index 0c282e8c5..4cf0c38e1 100644 --- a/docs/agents/19-navigation-and-link-audit.md +++ b/docs/agents/19-navigation-and-link-audit.md @@ -30,7 +30,7 @@ Not audited as broken links: Read-only inline Node audit result: ```text -totalMarkdown: 162 +totalMarkdown: 163 orphanishCount: 0 localBrokenCount: 0 ambiguousBareSectionIndexCount: 0 diff --git a/docs/agents/99-agent-index.md b/docs/agents/99-agent-index.md index 03c395bb0..90fe20189 100644 --- a/docs/agents/99-agent-index.md +++ b/docs/agents/99-agent-index.md @@ -1,6 +1,6 @@ # SSN AI Documentation Index -Status: framework plus source-backed backbone, product/install, install/update/version, standalone app source-window parity, overlays, theme pages, individual game pages, tip jar/credits, AI/cohost pages, event/effect overlays, live display utilities, specialized/legacy pages, diagnostic/helper pages, page capability routing, page processing inventory, API/integrations, common FAQ, common question intent router, common question fast path, common question evidence status, common question test set, support question phrasebook, support macro routing, common question coverage map, objective coverage/readiness audit, common misconceptions/boundaries, public claims boundary matrix, diagnostic decision tree, workflow setup decision tree, validation/refresh roadmap, runtime validation playbook, runtime evidence log, focused validation evidence log, navigation/link audit, support KB index, support evidence ledger, support history refresh playbook, support topic frequency index, support response playbook, support intake templates, support answer bank, privacy/security, custom-source, customization path decision matrix, customization source trace, troubleshooting, priority platform answer matrix, TikTok standalone app connector, remaining platform source, static/manual/helper sources, WebSocket/API source pages, communication/sensitive source scripts, embedded chat widget sources, live-commerce source scripts, webinar/event source scripts, creator-live-cam source scripts, popout/chat-only source scripts, event/community source scripts, independent live platform source scripts, video/broadcast platform source scripts, community/membership web-app source scripts, regional/emerging platform source scripts, special-case platform/helper source scripts, supported-site lookup/status/implementation map, source-file matrix, manifest row matrix, manifest source-load, platform capability matrix, Event Flow/Streamer.bot, first support-mining, desktop-app support, development/provider/test-asset, reference, control-surface crosswalk, action lookup, command source trace, API command validation matrix, API examples, URL option examples, URL parameter source trace, root page URL parameter matrix, subpage URL parameter matrix, settings, settings/session/storage source trace, settings change impact matrix, feature decision matrix, exact generated lookup, glossary, surface URL routing, how-to recipe, and preflight checklist passes. +Status: framework plus source-backed backbone, product/install, install/update/version, standalone app source-window parity, overlays, theme pages, individual game pages, tip jar/credits, AI/cohost pages, event/effect overlays, live display utilities, specialized/legacy pages, diagnostic/helper pages, page capability routing, page processing inventory, API/integrations, common FAQ, common question intent router, common question fast path, common question evidence status, common question test set, support question phrasebook, support macro routing, common question coverage map, objective coverage/readiness audit, common misconceptions/boundaries, public claims boundary matrix, diagnostic decision tree, workflow setup decision tree, validation/refresh roadmap, runtime validation playbook, runtime evidence log, focused validation evidence log, navigation/link audit, support KB index, support evidence ledger, support history refresh playbook, support topic frequency index, support response playbook, support intake templates, support answer bank, privacy/security, custom-source, customization path decision matrix, customization source trace, troubleshooting, priority platform answer and validation ledgers, TikTok standalone app connector, remaining platform source, static/manual/helper sources, WebSocket/API source pages, communication/sensitive source scripts, embedded chat widget sources, live-commerce source scripts, webinar/event source scripts, creator-live-cam source scripts, popout/chat-only source scripts, event/community source scripts, independent live platform source scripts, video/broadcast platform source scripts, community/membership web-app source scripts, regional/emerging platform source scripts, special-case platform/helper source scripts, supported-site lookup/status/implementation map, source-file matrix, manifest row matrix, manifest source-load, platform capability matrix, Event Flow/Streamer.bot, first support-mining, desktop-app support, development/provider/test-asset, reference, control-surface crosswalk, action lookup, command source trace, API command validation matrix, API examples, URL option examples, URL parameter source trace, root page URL parameter matrix, subpage URL parameter matrix, settings, settings/session/storage source trace, settings change impact matrix, feature decision matrix, exact generated lookup, glossary, surface URL routing, how-to recipe, and preflight checklist passes. ## Start Here @@ -15,7 +15,7 @@ Status: framework plus source-backed backbone, product/install, install/update/v - `16-runtime-validation-playbooks.md`: concrete runtime validation recipes and evidence templates for final-grade command, option, source, app, OBS, integration, AI/TTS, and support-claim validation. - `17-runtime-validation-evidence-log.md`: actual runtime validation evidence entries; currently includes controlled browser validation for `scoreboard.html` and `reactions.html`, plus a failed `multi-alerts.html` validation attempt. - `18-focused-validation-evidence-log.md`: focused validation evidence that is useful but not full runtime testing; currently includes settings config JSON, generated settings/URL/public-site metadata checks, Event Flow, Twitch provider, AI prompt builder, AI moderation, local model registry, provider fallback, local TTS, local AI asset, RAG fixture tests, and API command examples documentation consistency. -- `19-navigation-and-link-audit.md`: documentation navigation/link audit; current result is 162 Markdown files, zero unreferenced non-template pages, zero broken exact agent-doc Markdown references, and zero ambiguous bare section-index filenames. +- `19-navigation-and-link-audit.md`: documentation navigation/link audit; current result is 163 Markdown files, zero unreferenced non-template pages, zero broken exact agent-doc Markdown references, and zero ambiguous bare section-index filenames. ## Core Topic Pages @@ -30,7 +30,7 @@ Status: framework plus source-backed backbone, product/install, install/update/v ## Sections - `07-overlays-and-pages/index.md`: dock, featured, multi-alerts, theme pages, waitlist/polls/games, individual game pages, tip jar/credits, AI/cohost pages, event/effect overlays, live display utilities, specialized/legacy pages, diagnostic/helper pages, custom overlay, page capability routing, and page processing inventory passes started. -- `08-platform-sources/index.md`: source inventory, supported-site lookup/status/implementation map, source-file processing matrix, full manifest row matrix, manifest content-script matrix, platform capability matrix, priority platform answer matrix, plus YouTube, TikTok, TikTok standalone app connector, Twitch, Kick, Rumble, Facebook, Instagram, Discord, generic/custom, static/manual/helper source, WebSocket/API source-page, communication/sensitive source, embedded chat widget source, live-commerce source, webinar/event source, creator/live-cam source, popout/chat-only source, event/community source, independent live platform source, video/broadcast platform source, community/membership web-app source, regional/emerging platform source, and special-case platform/helper source passes started/complete. +- `08-platform-sources/index.md`: source inventory, supported-site lookup/status/implementation map, source-file processing matrix, full manifest row matrix, manifest content-script matrix, platform capability matrix, priority platform answer matrix, priority platform validation ledger, plus YouTube, TikTok, TikTok standalone app connector, Twitch, Kick, Rumble, Facebook, Instagram, Discord, generic/custom, static/manual/helper source, WebSocket/API source-page, communication/sensitive source, embedded chat widget source, live-commerce source, webinar/event source, creator/live-cam source, popout/chat-only source, event/community source, independent live platform source, video/broadcast platform source, community/membership web-app source, regional/emerging platform source, and special-case platform/helper source passes started/complete. - `09-api-and-integrations/index.md`: WebSocket/HTTP API, TTS, AI, OBS, StreamDeck/Companion, Event Flow, Streamer.bot, and API command validation heavy passes started. - `10-troubleshooting/index.md`: diagnostic decision tree, quick triage, extension capture, OBS overlay, desktop app, auth, settings/backup, and support-mined platform known-issue passes started/complete. - `11-support-kb/index.md`: support section map, first-answer router, triage evidence checklist, and privacy/source-priority rules. diff --git a/docs/agents/AGENT.md b/docs/agents/AGENT.md index b9b6d510a..f844af33d 100644 --- a/docs/agents/AGENT.md +++ b/docs/agents/AGENT.md @@ -86,6 +86,7 @@ For support-style answers: - `docs/agents/11-support-kb/common-question-coverage-map.md`: objective-level map of common question families to current docs. - `docs/agents/11-support-kb/common-misconceptions-and-boundaries.md`: common overclaims, stale-claim risks, and safer support wording. - `docs/agents/08-platform-sources/priority-platform-answer-matrix.md`: safe phrasing and first checks for high-volume platform capability, rich-event, send-back, and app/extension platform questions. +- `docs/agents/08-platform-sources/priority-platform-validation-ledger.md`: proof status, evidence labels, and validation targets for high-risk YouTube, TikTok, Twitch, Kick, Rumble, Facebook, Instagram, and Discord claims. - `docs/agents/13-reference/public-claims-boundary-matrix.md`: boundaries for broad public claims such as 100+/120+ sites, two-way chat, no API keys, free/open-source, AI/TTS, app behavior, plugins/customization, services, and support promises. - `docs/agents/11-support-kb/support-response-playbook.md`: ready-to-send response templates and follow-up prompts. - `docs/agents/11-support-kb/support-evidence-ledger.md`: support claim families, evidence status, and next validation targets. From 58e00463ab8cd1043d7630365289112d4339af19 Mon Sep 17 00:00:00 2001 From: steveseguin Date: Wed, 24 Jun 2026 08:10:45 -0400 Subject: [PATCH 23/30] feat(websocket): add test source for WebSocket message injection Add a new test source page (`testsource.html`) and content script (`testsource.js`) that dispatches custom `TestSourceMessage` events, allowing manual testing of chat overlay behavior without a live stream. The page includes predefined payloads, a custom message editor, and burst-send functionality. Updated `manifest.json` to register the new content script for the appropriate URLs. [auto-enhanced] --- manifest.json | 4 + sources/websocket/testsource.html | 287 ++++++++++++++++++++++++++++++ sources/websocket/testsource.js | 52 ++++++ 3 files changed, 343 insertions(+) create mode 100644 sources/websocket/testsource.html create mode 100644 sources/websocket/testsource.js diff --git a/manifest.json b/manifest.json index 3f7e2a181..9c3c92019 100644 --- a/manifest.json +++ b/manifest.json @@ -480,6 +480,10 @@ "js": ["./sources/websocket/irc.js"], "matches": ["https://socialstream.ninja/sources/websocket/irc*", "https://socialstream.ninja/beta/sources/websocket/irc*", "https://beta.socialstream.ninja/sources/websocket/irc*", "file:///C:/Users/steve/Code/social_stream/sources/websocket/irc.html*", "http://localhost:8080/*/irc.html*", "http://localhost:8181/*/irc.html*"] }, + { + "js": ["./sources/websocket/testsource.js"], + "matches": ["https://socialstream.ninja/sources/websocket/testsource*", "https://socialstream.ninja/beta/sources/websocket/testsource*", "https://beta.socialstream.ninja/sources/websocket/testsource*", "file:///C:/Users/steve/Code/social_stream/sources/websocket/testsource.html*", "http://localhost:8080/*/testsource.html*", "http://localhost:8181/*/testsource.html*"] + }, { "js": ["./sources/websocket/nostr.js"], "matches": ["https://socialstream.ninja/sources/websocket/nostr*", "https://socialstream.ninja/beta/sources/websocket/nostr*", "https://beta.socialstream.ninja/sources/websocket/nostr*", "http://localhost:8080/*/nostr.html*", "http://localhost:8181/*/nostr.html*"] diff --git a/sources/websocket/testsource.html b/sources/websocket/testsource.html new file mode 100644 index 000000000..194dad696 --- /dev/null +++ b/sources/websocket/testsource.html @@ -0,0 +1,287 @@ + + + + + Test Source - Social Stream Ninja + + + + +

Social Stream Test Source

+
+
+ + + + + + + + + + + + +
+ + +
+ + + +
+
+ +
+
Last payload sent
+
+
+
+ +
+
Fixed downstream test cases
+
+
+ + + + diff --git a/sources/websocket/testsource.js b/sources/websocket/testsource.js new file mode 100644 index 000000000..b4f08bdba --- /dev/null +++ b/sources/websocket/testsource.js @@ -0,0 +1,52 @@ +var settings = {}; + +window.addEventListener("TestSourceMessage", function (e) { + if (e.detail) { + pushMessage(e.detail); + } +}); + +function pushMessage(data) { + try { + chrome.runtime.sendMessage(chrome.runtime.id, { message: data }, function () {}); + } catch (e) { + console.error("Error sending test source message:", e); + } +} + +chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) { + try { + if ("getSource" == request) { + sendResponse("testsource"); + return; + } + if ("focusChat" == request) { + var input = document.getElementById("messageInput"); + if (input) { + input.focus(); + } + sendResponse(true); + return; + } + if (typeof request === "object" && "settings" in request) { + settings = request.settings || {}; + sendResponse(true); + return; + } + } catch (e) { + console.error("Error handling test source request:", e); + } + sendResponse(false); +}); + +chrome.runtime.sendMessage(chrome.runtime.id, { getSettings: true }, function (response) { + if (typeof chrome !== "undefined" && chrome.runtime && chrome.runtime.lastError) { + return; + } + response = response || {}; + if ("settings" in response) { + settings = response.settings || {}; + } +}); + +console.log("Social Stream Ninja test source injected"); From 8602b98447cd144d808bd4fda92b4b019d4ac2f1 Mon Sep 17 00:00:00 2001 From: steveseguin Date: Wed, 24 Jun 2026 08:21:05 -0400 Subject: [PATCH 24/30] docs(agents): add common question proof pack --- docs/agents/01-extraction-checklist.md | 1 + docs/agents/02-resource-processing-ledger.md | 4 +- docs/agents/11-support-kb/SITEMAP.md | 1 + .../common-question-coverage-map.md | 3 +- .../common-question-evidence-status.md | 1 + .../common-question-fast-path.md | 2 + .../common-question-proof-pack.md | 93 +++++++++++++++++++ docs/agents/11-support-kb/index.md | 4 +- .../11-support-kb/question-intent-router.md | 2 + .../11-support-kb/support-answer-bank.md | 2 +- docs/agents/13-reference/index.md | 1 + .../14-validation-and-refresh-roadmap.md | 2 +- ...-objective-coverage-and-readiness-audit.md | 9 +- docs/agents/19-navigation-and-link-audit.md | 2 +- docs/agents/99-agent-index.md | 5 +- docs/agents/AGENT.md | 3 +- 16 files changed, 121 insertions(+), 14 deletions(-) create mode 100644 docs/agents/11-support-kb/common-question-proof-pack.md diff --git a/docs/agents/01-extraction-checklist.md b/docs/agents/01-extraction-checklist.md index 72d697cb2..7166010f1 100644 --- a/docs/agents/01-extraction-checklist.md +++ b/docs/agents/01-extraction-checklist.md @@ -164,6 +164,7 @@ Add one entry per extraction pass. | 2026-06-24 | Codex | Common question fast-path matrix | Heavy support-routing pass | `11-support-kb/common-question-fast-path.md`, support/reference/audit/checklist/ledger updates | heavy-complete | Added compact answer-shape, must-check, and do-not-say routing for common SSN questions across product basics, cost, support, sites, modes, app, OBS, commands, API, URL parameters, settings, plugins/customization, source development, AI/TTS, privacy, bug reports, and testing claims. No runtime validation performed. | | 2026-06-24 | Codex | Curated support macro routing | Quick/Heavy support-macro pass | `11-support-kb/support-macro-routing.md`, support-source-map, stevesbot inventory, support/reference/checklist/ledger updates | quick/heavy-complete | Filtered safe curated macro playbooks down to SSN-relevant intake, safety/refusal, overlay blank, TikTok blank, Twitch auth, transparent overlay, platform-change, API no-op, app, AI/TTS, plugin, and escalation packet routing. VDO.Ninja-only macros were not imported except where OBS/TTS context overlaps SSN. No runtime validation performed. | | 2026-06-24 | Codex | Common question evidence status | Heavy evidence-status pass | `11-support-kb/common-question-evidence-status.md`, support/reference/audit/checklist/ledger updates | heavy-complete | Added evidence-strength and runtime-proof status labels for common SSN answer families, separating answer-ready orientation, source-backed, generated inventory, source-trace, support-derived, runtime-needed, and runtime-tested claims. No runtime validation performed. | +| 2026-06-24 | Codex | Common question proof pack | Heavy support-evidence routing pass | `11-support-kb/common-question-proof-pack.md`, support/reference/audit/checklist/ledger updates | heavy-complete | Added evidence requirements and minimum proof artifacts for stronger answers about common SSN questions: product/cost/support, sites, platform features, app/extension modes, install/update, troubleshooting, OBS, commands/API, URL options, settings, customization/plugins, new sources, AI/TTS/RAG, privacy, and testing claims. No runtime validation performed. | | 2026-06-24 | Codex | Common question test set | Heavy support-routing benchmark pass | `11-support-kb/common-question-test-set.md`, support/index/sitemap/ledger/audit updates | heavy-complete | Added benchmark-style test prompts for product/cost/support, install/modes, source capture, platform behavior, commands/API, URL/settings/sessions, overlays/pages, AI/TTS/RAG, customization/plugins/development, privacy, and testing claims. Each row records expected first doc, secondary proof docs, required caveat, and fail condition. This validates answer routing only, not product runtime behavior. | | 2026-06-24 | Codex | Support history refresh playbook | Heavy support-refresh workflow pass | `11-support-kb/support-history-refresh-playbook.md`, support indexes/ledger/audit updates | heavy-complete | Added a safe repeatable support-history refresh workflow with aggregate SQLite query pack, current seed counts from `knowledge.sqlite` and `stevesbot.sqlite`, latest QA export reference, raw archive gate, stale-claim decision tree, and required downstream doc updates. Counts are priority signals only, not runtime/product proof. | | 2026-06-24 | Codex | App, extension, and mode crosswalk | Heavy support-routing/reference pass | `13-reference/app-extension-mode-crosswalk.md`, support/reference indexes/checklist/ledger/audit updates | heavy-complete | Added first-stop routing for Chrome extension vs standalone app vs hosted pages, local pages, Lite, Firefox, WebSocket/API source pages, and custom sources. Includes safe answer rules, surface matrix, app-vs-extension decision matrix, common confusion points, troubleshooting routes, recommended answer shapes, and overclaim guardrails. Not runtime-tested. | diff --git a/docs/agents/02-resource-processing-ledger.md b/docs/agents/02-resource-processing-ledger.md index e5359757a..a963993b2 100644 --- a/docs/agents/02-resource-processing-ledger.md +++ b/docs/agents/02-resource-processing-ledger.md @@ -32,7 +32,7 @@ Use this file to answer: "Has this resource been processed already, and how deep | Resource Area | Current Depth | Main Output Docs | Remaining Need | | --- | --- | --- | --- | | Overall objective coverage/readiness | heavy audit plus narrow runtime and focused validation evidence | `15-objective-coverage-and-readiness-audit.md`, `99-agent-index.md`, `14-validation-and-refresh-roadmap.md`, `16-runtime-validation-playbooks.md`, `17-runtime-validation-evidence-log.md`, `18-focused-validation-evidence-log.md` | Keep coverage current after new passes; do not mark the whole docs objective complete until runtime-tested claims and proof gaps are resolved. Use the runtime playbooks to record evidence before promoting claims. | -| Agent documentation navigation | quick/focused docs audit plus static viewer/sitemaps | `docs/index.html`, `docs/agents/SITEMAP.md`, section `docs/agents/*/SITEMAP.md` files, `19-navigation-and-link-audit.md`, `99-agent-index.md`, `AGENT.md`, section indexes | Static client-side Markdown viewer added at `docs/index.html`; root and per-section sitemap Markdown files added under `docs/agents`. Current focused audit covers 163 Markdown files with zero unreferenced non-template pages, zero broken exact agent-doc Markdown refs, and zero ambiguous bare section-index filenames. Refresh after sitemap changes and large doc-growth. | +| Agent documentation navigation | quick/focused docs audit plus static viewer/sitemaps | `docs/index.html`, `docs/agents/SITEMAP.md`, section `docs/agents/*/SITEMAP.md` files, `19-navigation-and-link-audit.md`, `99-agent-index.md`, `AGENT.md`, section indexes | Static client-side Markdown viewer added at `docs/index.html`; root and per-section sitemap Markdown files added under `docs/agents`. Current focused audit covers 164 Markdown files with zero unreferenced non-template pages, zero broken exact agent-doc Markdown refs, and zero ambiguous bare section-index filenames. Refresh after sitemap changes and large doc-growth. | | Runtime validation workflow | heavy planning plus evidence log | `14-validation-and-refresh-roadmap.md`, `16-runtime-validation-playbooks.md`, `17-runtime-validation-evidence-log.md`, `12-development/testing-and-validation.md` | Continue executing playbooks and recording real runtime evidence before promoting commands, URL options, sources, app flows, OBS pages, integrations, provider behavior, or support claims to tested. | | Existing test and validation assets | heavy inventory/routing plus focused config/metadata/Node/browser-fixture evidence | `12-development/test-asset-matrix.md`, `12-development/testing-and-validation.md`, `16-runtime-validation-playbooks.md`, `18-focused-validation-evidence-log.md` | Focused evidence now covers settings config JSON validation, generated settings/URL/public-site metadata checks with duplicate metadata findings, selected Event Flow internals, Twitch subgift normalization, AI prompt builder smoke behavior, profanity/moderation checks, local browser model registry checks, OpenCode Zen fallback checks, Kokoro and Kitten static TTS asset wiring, Transformers remote-host defaults, RAG fixture E2E/benchmark behavior, plus a failing Piper asset expectation. Keep the matrix current when npm aliases, Node tests, browser fixtures, shell validators, metadata checkers, or Playwright scripts change; run focused assets before using them as evidence. | | Product overview and install surfaces | heavy | `01-product-map.md`, `02-installation-and-surfaces.md`, `13-reference/app-extension-mode-crosswalk.md`, `13-reference/install-update-version-guide.md`, `13-reference/public-claims-boundary-matrix.md` | Intense claim reconciliation only if publishing user-facing final docs; app auto-update and exact extension export/import behavior still need verification. | @@ -50,7 +50,7 @@ Use this file to answer: "Has this resource been processed already, and how deep | API and integrations | heavy plus source trace/crosswalk plus focused examples consistency check | `09-api-and-integrations/*`, `13-reference/control-surface-crosswalk.md`, `13-reference/action-command-index.md`, `13-reference/command-action-source-trace.md`, `13-reference/api-command-validation-matrix.md`, `13-reference/api-command-examples.md`, `18-focused-validation-evidence-log.md` | Static examples extraction found 29 action examples and, after docs updates, zero missing entries across action index, validation matrix, and source trace; `content4`/numbered channel caveats were added to the matrix and trace. Remaining needs: runtime command validation, callback/label/channel validation, and integration edge cases. | | Event Flow and Streamer.bot | heavy plus focused Event Flow Node-test evidence | `09-api-and-integrations/event-flow-editor.md`, `streamerbot.md`, `18-focused-validation-evidence-log.md` | Event Flow custom JS, compare-property, template/counter, OBS system trigger, and play-media duration tests passed. Remaining needs: editor UI, Flow Actions overlay, OBS, webhook, relay, TTS, Spotify, MIDI, points, send-message, import/export, and integration runtime validation. | | TTS and AI | heavy plus focused AI prompt, moderation, local model, provider fallback, local asset, and RAG fixture evidence | `09-api-and-integrations/tts.md`, `ai-features.md`, `07-overlays-and-pages/ai-cohost-pages.md`, `13-reference/public-claims-boundary-matrix.md`, `18-focused-validation-evidence-log.md`, reference docs | AI prompt builder, profanity/moderation, local browser model registry, OpenCode Zen fallback, Kokoro, Kitten, Transformers, and RAG fixture checks have focused evidence; Piper focused test currently fails. Remaining needs: provider-specific setup, live moderation quality, real RAG upload/delete/provider workflows, model download/runtime behavior, cohost/generated overlay page behavior, `aioverlay.html` runtime/OBS behavior, app behavior, and cost/limit verification. | -| Troubleshooting support docs | heavy plus frequency/router/phrasebook/macro/evidence-status/test-set/refresh-playbook pass | `10-troubleshooting/*`, `11-support-kb/*`, `13-reference/preflight-checklists.md`, `13-reference/privacy-security-and-secrets.md` | Source-check every support-derived claim before treating as final. Use `10-troubleshooting/diagnostic-decision-tree.md` for symptom classification, `13-reference/preflight-checklists.md` for before-stream/update prevention checks, `13-reference/privacy-security-and-secrets.md` for URL/log/screenshot/settings redaction and secret leak response, `11-support-kb/index.md` for first-answer routing, `11-support-kb/question-intent-router.md` for plain-language user wording to canonical route selection, `11-support-kb/common-question-fast-path.md` for compact answer-shape routing, `11-support-kb/common-question-evidence-status.md` for evidence-strength and runtime-proof status by common answer family, `11-support-kb/common-question-test-set.md` for benchmark-style prompt routing checks, `11-support-kb/support-history-refresh-playbook.md` for safe aggregate support-history refreshes, `11-support-kb/support-question-phrasebook.md` for paraphrased support-history wording patterns, `11-support-kb/support-macro-routing.md` for SSN-filtered short macros from curated support playbooks, `11-support-kb/common-question-coverage-map.md` for objective coverage, `11-support-kb/support-topic-frequency-index.md` for SSN-filtered support topic priorities, `11-support-kb/common-misconceptions-and-boundaries.md` for overclaim boundaries, `11-support-kb/support-evidence-ledger.md` for claim evidence status, `11-support-kb/support-response-playbook.md` for reply phrasing, and `11-support-kb/support-intake-templates.md` for redaction-safe evidence collection. | +| Troubleshooting support docs | heavy plus frequency/router/phrasebook/macro/evidence-status/proof-pack/test-set/refresh-playbook pass | `10-troubleshooting/*`, `11-support-kb/*`, `13-reference/preflight-checklists.md`, `13-reference/privacy-security-and-secrets.md` | Source-check every support-derived claim before treating as final. Use `10-troubleshooting/diagnostic-decision-tree.md` for symptom classification, `13-reference/preflight-checklists.md` for before-stream/update prevention checks, `13-reference/privacy-security-and-secrets.md` for URL/log/screenshot/settings redaction and secret leak response, `11-support-kb/index.md` for first-answer routing, `11-support-kb/question-intent-router.md` for plain-language user wording to canonical route selection, `11-support-kb/common-question-fast-path.md` for compact answer-shape routing, `11-support-kb/common-question-evidence-status.md` for evidence-strength and runtime-proof status by common answer family, `11-support-kb/common-question-proof-pack.md` for minimum evidence artifacts before stronger answers, `11-support-kb/common-question-test-set.md` for benchmark-style prompt routing checks, `11-support-kb/support-history-refresh-playbook.md` for safe aggregate support-history refreshes, `11-support-kb/support-question-phrasebook.md` for paraphrased support-history wording patterns, `11-support-kb/support-macro-routing.md` for SSN-filtered short macros from curated support playbooks, `11-support-kb/common-question-coverage-map.md` for objective coverage, `11-support-kb/support-topic-frequency-index.md` for SSN-filtered support topic priorities, `11-support-kb/common-misconceptions-and-boundaries.md` for overclaim boundaries, `11-support-kb/support-evidence-ledger.md` for claim evidence status, `11-support-kb/support-response-playbook.md` for reply phrasing, and `11-support-kb/support-intake-templates.md` for redaction-safe evidence collection. | | Development docs | heavy | `12-development/*`, `12-development/test-asset-matrix.md`, `13-reference/customization-path-decision-matrix.md`, `13-reference/customization-source-trace.md`, `13-reference/customization-plugin-recipes.md`, `13-reference/custom-plugins-and-extensions.md` | Expand code-change workflows with exact file responsibilities and validate custom-code/app-extension parity. Keep test asset routing current. | ## High-Value Files Already Used diff --git a/docs/agents/11-support-kb/SITEMAP.md b/docs/agents/11-support-kb/SITEMAP.md index ecf2af99c..e7d24a4c3 100644 --- a/docs/agents/11-support-kb/SITEMAP.md +++ b/docs/agents/11-support-kb/SITEMAP.md @@ -13,6 +13,7 @@ Use this file to navigate this folder without scanning the filesystem. - [Common Question Coverage Map](../11-support-kb/common-question-coverage-map.md) - Use this page to check whether the current AI docs cover the common SSN question family a user is asking about. - [Common Question Evidence Status](../11-support-kb/common-question-evidence-status.md) - Use this page when an agent has already found the likely answer route, but needs to know how strongly the current docs support the answer. - [Common Question Fast Path](../11-support-kb/common-question-fast-path.md) - Use this page when an agent needs to answer a common SSN question quickly but still choose the right proof docs before making a precise claim. +- [Common Question Proof Pack](../11-support-kb/common-question-proof-pack.md) - Use this page when an agent needs to know what evidence is required before giving a stronger answer to common SSN questions. - [Common Question Test Set](../11-support-kb/common-question-test-set.md) - Use this page to test whether an AI agent can route and answer common SSN prompts without guessing, overclaiming, leaking secrets, or treating static evidence as runtime testing. - [Common Support Questions](../11-support-kb/common-questions.md) - For first-stop routing, use docs/agents/11-support-kb/index.md. For objective coverage by question family, use common-question-coverage-map.md. For concise support-response patterns, use support-answer-bank.md. - [Historical Support Issues](../11-support-kb/historical-issues.md) - This file tracks recurring SSN support issues found in historical support summaries, playbooks, Q&A exports, and SQLite summary tables. It is not a final troubleshooting page. It is a mined evidence map for future docs and source verification. diff --git a/docs/agents/11-support-kb/common-question-coverage-map.md b/docs/agents/11-support-kb/common-question-coverage-map.md index 9b3dcb65e..d0261dac1 100644 --- a/docs/agents/11-support-kb/common-question-coverage-map.md +++ b/docs/agents/11-support-kb/common-question-coverage-map.md @@ -10,7 +10,7 @@ This is a coverage map, not a final answer page. Route to the listed docs, then For support-history frequency and priority signals, use `support-topic-frequency-index.md`. -For plain-language user wording and first-route selection, use `question-intent-router.md` before choosing a narrow topic page. For a compact answer-shape matrix, use `common-question-fast-path.md`. For evidence strength and runtime-proof status by common answer type, use `common-question-evidence-status.md`. For a benchmark-style prompt set that tests whether agents route and answer common questions without overclaiming, use `common-question-test-set.md`. For paraphrased real-world wording patterns from support history, use `support-question-phrasebook.md`. For short macro-style support replies from curated playbooks, use `support-macro-routing.md`. +For plain-language user wording and first-route selection, use `question-intent-router.md` before choosing a narrow topic page. For a compact answer-shape matrix, use `common-question-fast-path.md`. For evidence strength and runtime-proof status by common answer type, use `common-question-evidence-status.md`. For the evidence artifacts needed before stronger answers, use `common-question-proof-pack.md`. For a benchmark-style prompt set that tests whether agents route and answer common questions without overclaiming, use `common-question-test-set.md`. For paraphrased real-world wording patterns from support history, use `support-question-phrasebook.md`. For short macro-style support replies from curated playbooks, use `support-macro-routing.md`. ## Coverage Labels @@ -29,6 +29,7 @@ For plain-language user wording and first-route selection, use `question-intent- | What is the fastest safe answer path for a common question? | covered-heavy | `11-support-kb/common-question-fast-path.md` | routed topic docs and current source/runtime evidence | | Can an agent test common SSN prompt routing and safe-answer behavior? | covered-heavy | `11-support-kb/common-question-test-set.md` | routed topic docs, common overclaim docs, and runtime evidence where required | | How strong is the evidence for a common answer? | covered-heavy | `11-support-kb/common-question-evidence-status.md` | routed topic docs, `support-evidence-ledger.md`, runtime evidence if any | +| What proof is needed before giving a stronger answer? | covered-heavy | `11-support-kb/common-question-proof-pack.md` | routed topic docs, source/config, focused evidence, and runtime evidence where required | | Is SSN free? | covered-heavy | `13-reference/free-paid-and-support-boundaries.md` | `11-support-kb/support-evidence-ledger.md` | | What can cost money? | covered-heavy | `13-reference/free-paid-and-support-boundaries.md` | `09-api-and-integrations/tts.md`, `ai-features.md` | | Can I repeat broad public claims like 100+/120+ sites, most platforms, two-way chat, no API keys, or free? | covered-heavy | `13-reference/public-claims-boundary-matrix.md` | routed topic docs and current source/runtime evidence | diff --git a/docs/agents/11-support-kb/common-question-evidence-status.md b/docs/agents/11-support-kb/common-question-evidence-status.md index f88e94352..a6528cf67 100644 --- a/docs/agents/11-support-kb/common-question-evidence-status.md +++ b/docs/agents/11-support-kb/common-question-evidence-status.md @@ -11,6 +11,7 @@ This complements: - `common-question-fast-path.md` for fast answer shape. - `question-intent-router.md` for first-route selection. - `common-question-coverage-map.md` for objective coverage. +- `common-question-proof-pack.md` for the evidence artifacts required before stronger common-question answers. - `support-evidence-ledger.md` for support-history claim families. - `13-reference/public-claims-boundary-matrix.md` for broad public claims. - `15-objective-coverage-and-readiness-audit.md` for the whole docs objective. diff --git a/docs/agents/11-support-kb/common-question-fast-path.md b/docs/agents/11-support-kb/common-question-fast-path.md index 00b1865b0..9114242c3 100644 --- a/docs/agents/11-support-kb/common-question-fast-path.md +++ b/docs/agents/11-support-kb/common-question-fast-path.md @@ -16,6 +16,7 @@ This page is intentionally compact. It points to the deeper docs rather than res - `docs/agents/11-support-kb/common-misconceptions-and-boundaries.md` - `docs/agents/11-support-kb/support-evidence-ledger.md` - `docs/agents/11-support-kb/common-question-evidence-status.md` +- `docs/agents/11-support-kb/common-question-proof-pack.md` - `docs/agents/13-reference/index.md` - `docs/agents/13-reference/public-claims-boundary-matrix.md` - `docs/agents/15-objective-coverage-and-readiness-audit.md` @@ -27,6 +28,7 @@ This page is intentionally compact. It points to the deeper docs rather than res 3. Apply the "Must Check" column before making exact claims. 4. Avoid the "Do Not Say" wording unless the linked proof docs and runtime evidence support it. 5. Use `common-question-evidence-status.md` when deciding whether the answer is only orientation, source-backed, generated inventory, source-traced, support-derived, or runtime-tested. +6. Use `common-question-proof-pack.md` before upgrading a cautious answer into a stronger claim. ## Fast Path Matrix diff --git a/docs/agents/11-support-kb/common-question-proof-pack.md b/docs/agents/11-support-kb/common-question-proof-pack.md new file mode 100644 index 000000000..ca534e220 --- /dev/null +++ b/docs/agents/11-support-kb/common-question-proof-pack.md @@ -0,0 +1,93 @@ +# Common Question Proof Pack + +Status: heavy support-evidence routing pass on 2026-06-24. This is not runtime validation. + +## Purpose + +Use this page when an agent already has a likely short answer, but needs to know what evidence is required before giving a stronger or more exact answer. + +This page complements: + +- `common-question-fast-path.md` for fast answer shape. +- `support-answer-bank.md` for short practical replies. +- `common-question-evidence-status.md` for evidence-strength labels. +- `support-response-playbook.md` for ready-to-send support wording. +- `../16-runtime-validation-playbooks.md` for actual runtime validation recipes. + +Rule: a proof pack does not prove a claim by itself. It lists what must be checked. Use the linked docs and current source before making exact claims. + +## Evidence Levels + +| Level | Good For | Not Good For | +| --- | --- | --- | +| `answer-route` | Picking the right doc and first caveat. | Saying a feature works. | +| `source-backed` | Explaining current code/doc behavior cautiously. | Saying it was tested in browser/app/OBS/live platform. | +| `generated-inventory` | Counts, lookup tables, setting keys, URL params, public cards. | Runtime health or platform availability. | +| `source-trace` | Explaining handlers, parser paths, storage, command acceptance, and caveats. | External side effects or user workflow success. | +| `focused-test` | Narrow deterministic behavior, fixtures, or static checks. | Broad user-facing runtime claims. | +| `runtime-proof` | Saying a specific workflow was tested, within its exact limits. | Broader surfaces, modes, pages, platforms, or account states not covered by the run. | + +## Strong Answer Gate + +Before answering with "yes, this works", "this is supported", "this command does X", "this option controls Y", or "this was tested", collect: + +1. The exact user goal and surface: extension, app, hosted page, local page, OBS, API, WebSocket source page, Lite, or Firefox. +2. The exact mode: DOM capture, popout/chat-only, static/manual helper, WebSocket/API source, app source window, Event Flow, API command, URL parameter, or popup setting. +3. The canonical doc route. +4. The current source/config/metadata route when the claim is exact. +5. The proof type: answer-route, source-backed, generated-inventory, source-trace, focused-test, or runtime-proof. +6. What was not checked. + +## Proof Packs By Common Question + +| Question Family | Short Answer Allowed From Routing Docs | Evidence To Inspect Before Strong Claim | Strong Claim Requires | Do Not Say | +| --- | --- | --- | --- | --- | +| What is SSN? | SSN captures chat/events and routes them to dock, overlays, API, TTS, AI, and automation. | `01-product-map.md`, `13-reference/features-and-capabilities.md` | Only needed for exact feature/surface claims. | "It is only an OBS overlay." | +| Is SSN free? | SSN itself is free/open source; third-party services can cost money. | `13-reference/free-paid-and-support-boundaries.md`, `13-reference/public-claims-boundary-matrix.md` | Current provider/platform docs for exact pricing, quotas, or limits. | "Everything is free." | +| Is support paid or guaranteed? | Support is best-effort; donations are gifts, not support contracts. | `13-reference/support-resources-and-escalation.md`, `support-evidence-ledger.md` | Public support/donation wording refresh if this changes. | "A donation guarantees support." | +| How many sites are supported? | SSN has a large public supported-site list; current generated docs route 139 public cards. | `08-platform-sources/supported-sites-lookup.md`, `public-site-support-status.md`, `public-site-implementation-map.md`, `docs/js/sites.js` | Re-run generated extraction and public-card validation; runtime health validation for "works today." | "Every listed site fully works." | +| Is this site supported? | Check public card, setup type, source route, and mode. | `supported-sites-lookup.md`, `public-site-support-status.md`, `public-site-implementation-map.md`, `manifest-row-matrix.md`, exact source doc | Browser/app/live page validation for current health. | "Listed means every URL and feature works." | +| Platform rich events, gifts, rewards, follows, viewer counts, moderation, send-back | Depends on platform, source mode, auth, role, scopes, and event family. | `priority-platform-answer-matrix.md`, `priority-platform-validation-ledger.md`, `platform-capability-matrix.md`, exact platform doc/source | Source-line trace plus live/app/API proof for that exact platform/mode/event. | "Plain chat support means rich events/send-back work." | +| Extension or standalone app? | Extension for normal browser/cookie workflows; app for managed source windows or some throttling/source-window workflows. | `13-reference/app-extension-mode-crosswalk.md`, `modes-and-capability-matrix.md`, `04-standalone-app-source-windows.md` | Real app and extension comparison for the exact platform/workflow. | "The app fixes every login problem." | +| Install or update manually | Load unpacked from a stable extracted folder; update by replacing files and reloading, not uninstalling first. | `13-reference/install-update-version-guide.md`, `02-installation-and-surfaces.md`, `10-troubleshooting/settings-loss-and-backups.md` | Runtime check only for exact browser/app update behavior. | "Uninstall first" without backup/export warning. | +| Chat not appearing anywhere | Split source capture from display; prove dock first. | `10-troubleshooting/diagnostic-decision-tree.md`, `quick-triage.md`, `extension-not-capturing.md`, exact platform doc | Current platform/source validation if the issue is platform-specific. | "OBS is broken" before dock/source checks. | +| Dock works but OBS/overlay is blank | Capture likely works; check overlay URL/session/page purpose/browser preview/OBS refresh/CSS. | `10-troubleshooting/obs-overlay-display.md`, `surface-url-cheatsheet.md`, `07-overlays-and-pages/page-capability-matrix.md` | Browser or OBS validation for that exact page and payload. | "Reinstall SSN first." | +| Which page or URL should I open? | Pick by job: source page, dock, featured, theme, tool page, API test page, or diagnostic helper. | `13-reference/surface-url-cheatsheet.md`, `workflow-setup-decision-tree.md`, `how-to-recipes.md` | Page-specific runtime validation for exact parameter or payload behavior. | "Always open dock only." | +| What command/action should I use? | First classify viewer command, API action, URL parameter, Event Flow action, MIDI/hotkey, or page-local control. | `13-reference/control-surface-crosswalk.md`, `commands-and-actions.md`, `action-command-index.md` | Source-trace or runtime proof for high-side-effect or rare actions. | "All commands use the same syntax." | +| API command says success but nothing changes | Relay acceptance is not proof the target acted. | `api-command-validation-matrix.md`, `command-action-source-trace.md`, `websocket-http-api.md`, target page doc | Runtime proof with exact action, transport, session, channel, target page/source, label, and observed result. | "The API success response proves it worked." | +| What URL option controls this? | Use generated URL parameter lookup, then verify target page parser. | `url-parameter-index.md`, `url-parameter-source-trace.md`, `root-page-url-parameter-matrix.md`, `subpage-url-parameter-matrix.md` | Runtime proof for exact page/option/load-time behavior. | "Every parameter works on every page." | +| Setting changed but nothing happened | Classify popup setting, URL parameter, generated link, app source state, provider/auth value, or page-local state. | `settings-change-impact-matrix.md`, `settings-session-storage-source-trace.md`, `settings-key-index.md`, `url-parameter-index.md` | Browser/app/runtime validation for live update, reload, migration, export/import, or app parity. | "All settings update live." | +| Make a plugin or customize SSN | "Plugin" can mean custom overlay, URL/CSS, local custom JS, uploaded user function, Event Flow, API client, or first-class source. | `customization-path-decision-matrix.md`, `customization-plugin-recipes.md`, `custom-plugins-and-extensions.md`, `customization-source-trace.md` | Runtime proof for local/hosted/app path, payload handling, custom code loading, and security boundaries. | "There is one plugin zip installer." | +| Add a new source/platform | Add source file, manifest route, site/docs metadata, payload compatibility, and extension/app validation. | `12-development/adding-a-source.md`, `08-platform-sources/generic-and-custom-sources.md`, `manifest-content-scripts.md`, `manifest-row-matrix.md` | Code review plus extension/app/browser validation with controlled payloads. | "Only edit the app fallback mirror." | +| TTS or AI is free/available | SSN integrates with local/system and provider-backed paths; external providers control keys, quotas, pricing, and limits. | `09-api-and-integrations/tts.md`, `ai-features.md`, `free-paid-and-support-boundaries.md`, `public-claims-boundary-matrix.md` | Current provider docs plus runtime/provider validation for exact availability, pricing, model, voice, audio, or RAG workflow. | "All AI/TTS modes are free." | +| Privacy, logs, screenshots, settings, URLs | Share only redacted evidence. | `13-reference/privacy-security-and-secrets.md`, `support-intake-templates.md`, `support-resources-and-escalation.md` | File-by-file privacy review for logs/settings/screenshots. | "Paste your key/session/webhook." | +| Was this tested? | Only real browser/app/OBS/API/platform workflows count as tested. | `16-runtime-validation-playbooks.md`, `17-runtime-validation-evidence-log.md`, `18-focused-validation-evidence-log.md` | A dated evidence entry matching the exact claim. | "Source-checked means tested." | + +## Minimum Proof Artifacts + +| Claim Type | Minimum Artifact | +| --- | --- | +| Capture works | Source/platform/mode, new message or controlled payload, dock receipt, same session proof, surface used, not-tested notes. | +| Overlay/page works | Page URL with secrets redacted, source payload, browser preview or OBS result, page mode/label/session, not-tested notes. | +| API action works | Action name, transport, encoded payload, target page/source open, session/channel/label, observed page/source effect, callback/error behavior. | +| URL parameter works | Target page, exact parameter/value, load/refresh behavior, observed DOM/behavior change, conflicting setting/default notes. | +| Setting works | Setting key, UI/app surface, stored value, source/page reload or live update behavior, extension/app parity notes. | +| Platform rich event works | Platform/mode/auth role, sample payload, downstream dock/API/overlay receipt, event field notes, not-tested event families. | +| Send-back works | Platform/mode, signed-in account, scopes/role, source-control path, safe sent message, failure behavior, policy caveat. | +| Customization works | Path used, local/hosted/app boundary, payload sample, error behavior, secret review, fallback/rollback plan. | +| AI/TTS/RAG works | Provider/local path, model/voice/settings, input, output, cost/key/secret boundary, browser/app/OBS/audio notes. | + +## How To Record A Promoted Claim + +When a common question moves from cautious orientation to stronger evidence: + +1. Add runtime evidence to `../17-runtime-validation-evidence-log.md` or focused evidence to `../18-focused-validation-evidence-log.md`. +2. Update the narrow topic doc. +3. Update `common-question-evidence-status.md` if the common answer strength changed. +4. Update `support-evidence-ledger.md` if a support claim was promoted, narrowed, or rejected. +5. Add a row to `../01-extraction-checklist.md`. +6. Update `../15-objective-coverage-and-readiness-audit.md` only if objective-level readiness changed. + +## Current Non-Completion Boundary + +This page improves answer discipline for common questions, but it does not complete runtime validation. It should make agents less likely to overclaim while they continue validating commands, options, supported sites, modes, customization paths, AI/TTS, app workflows, OBS overlays, and platform behavior. diff --git a/docs/agents/11-support-kb/index.md b/docs/agents/11-support-kb/index.md index 7f7118b25..d9b04fb19 100644 --- a/docs/agents/11-support-kb/index.md +++ b/docs/agents/11-support-kb/index.md @@ -16,6 +16,7 @@ Start here when the user asks a practical question in plain language, then route - `support-question-phrasebook.md`: paraphrased support-history wording patterns tied to canonical docs and safe answer boundaries. - `common-question-coverage-map.md`: objective-level coverage map for common question families and remaining validation gaps. - `common-question-evidence-status.md`: evidence-strength and runtime-proof status for common SSN answer families. +- `common-question-proof-pack.md`: evidence requirements before stronger answers about commands, options, supported sites, modes, customization, costs, privacy, testing, and platform behavior. - `common-question-test-set.md`: benchmark-style prompt set for checking whether agents can route and answer common SSN questions without guessing or overclaiming. - `../15-objective-coverage-and-readiness-audit.md`: objective requirement coverage, answer-readiness labels, completion evidence, and remaining proof gaps. - `../16-runtime-validation-playbooks.md`: runtime validation recipes and evidence templates for promoting support claims from source-backed to tested. @@ -43,6 +44,7 @@ Start here when the user asks a practical question in plain language, then route | "What is SSN?" | `question-intent-router.md` | `support-answer-bank.md` product basics, `01-product-map.md` | | "What is the fastest safe answer path for this common question?" | `common-question-fast-path.md` | Routed topic docs and current source | | "Can I test whether an agent answers common SSN questions correctly?" | `common-question-test-set.md` | Routed topic docs, common overclaim docs, and runtime evidence where required | +| "What proof do I need before making a stronger answer?" | `common-question-proof-pack.md` | Routed topic docs, source/config, and runtime evidence where required | | "Is it free?" | `question-intent-router.md` | `support-answer-bank.md` product basics, `13-reference/free-paid-and-support-boundaries.md`, `13-reference/public-claims-boundary-matrix.md` | | "What should I not overpromise?" | `common-misconceptions-and-boundaries.md` | Routed topic docs and current source | | "Can I repeat a public claim like 120+ sites, free, two-way, or no API keys?" | `../13-reference/public-claims-boundary-matrix.md` | Routed topic docs and current source | @@ -73,7 +75,7 @@ Start here when the user asks a practical question in plain language, then route | "What information should I ask the user for?" | `support-intake-templates.md` | Routed topic docs and current source | | "Do these AI docs already cover this kind of question?" | `common-question-coverage-map.md` | The routed topic docs and current source | | "How close are these AI docs to done?" | `../15-objective-coverage-and-readiness-audit.md` | `../14-validation-and-refresh-roadmap.md`, checklist, ledger | -| "How strong is the evidence for this common answer?" | `common-question-evidence-status.md` | Routed topic docs, `support-evidence-ledger.md`, runtime evidence if any | +| "How strong is the evidence for this common answer?" | `common-question-evidence-status.md` | `common-question-proof-pack.md`, routed topic docs, `support-evidence-ledger.md`, runtime evidence if any | | "How do I safely refresh support-history counts and prompt patterns?" | `support-history-refresh-playbook.md` | `stevesbot-resource-inventory.md`, `mining-method.md`, `support-source-map.md` | | "Can I say this was tested?" | `../16-runtime-validation-playbooks.md` | `support-evidence-ledger.md`, routed topic docs, current source | | "How do users usually phrase this problem?" | `support-question-phrasebook.md` | `question-intent-router.md`, routed topic docs, current source | diff --git a/docs/agents/11-support-kb/question-intent-router.md b/docs/agents/11-support-kb/question-intent-router.md index 3628f226d..ecf8b8a6b 100644 --- a/docs/agents/11-support-kb/question-intent-router.md +++ b/docs/agents/11-support-kb/question-intent-router.md @@ -11,6 +11,7 @@ This page complements: - `docs/agents/11-support-kb/index.md` for the support KB section map. - `common-question-fast-path.md` for compact answer selection before opening deeper docs. - `common-question-evidence-status.md` for evidence-strength and runtime-proof status by common answer type. +- `common-question-proof-pack.md` for evidence requirements before stronger common-question answers. - `support-answer-bank.md` for short answer patterns. - `support-question-phrasebook.md` for paraphrased real support wording patterns. - `support-macro-routing.md` for short macro-style replies from curated support playbooks. @@ -82,6 +83,7 @@ Rule: do not stop at this page for fragile claims. If the answer depends on sele | "Is this a bug?" | Escalation/support | `../13-reference/support-resources-and-escalation.md` | Repro details, versions, exact mode, current source, safe evidence. | | "What should I ask the user for?" | Intake template | `support-intake-templates.md` | Only collect relevant details and redact secrets. | | "How strong is the evidence for this answer?" | Evidence status | `common-question-evidence-status.md` | Do not say runtime-tested unless exact runtime evidence exists. | +| "What proof do I need before I say this works?" | Strong answer evidence | `common-question-proof-pack.md` | Match proof to the exact surface, mode, command, option, page, platform, or provider. | | "Is there a short macro for this?" | Support macro | `support-macro-routing.md` | Confirm routed docs and avoid overclaims. | | "Can you write the support reply?" | Response template | `support-response-playbook.md` | Confirm routed docs and avoid overclaims. | diff --git a/docs/agents/11-support-kb/support-answer-bank.md b/docs/agents/11-support-kb/support-answer-bank.md index 1c67166a8..d1428a1e5 100644 --- a/docs/agents/11-support-kb/support-answer-bank.md +++ b/docs/agents/11-support-kb/support-answer-bank.md @@ -2,7 +2,7 @@ Status: heavy support-answer pass from current agent docs, public docs, source inventories, and support-mining summaries on 2026-06-24. -Use this page when an AI agent needs a short, practical answer to a common SSN support question. For first-stop routing by user intent, start with `question-intent-router.md` or `docs/agents/11-support-kb/index.md`. For a compact "answer shape, must-check, do-not-say" matrix, use `common-question-fast-path.md`. For command/option/setting/mode confusion, use `../13-reference/control-surface-crosswalk.md`. For paraphrased real-world wording patterns, use `support-question-phrasebook.md`. For ready-to-send support templates, use `support-response-playbook.md`. For SSN-filtered macro-style replies from curated support playbooks, use `support-macro-routing.md`. For evidence-strength and runtime-proof status, use `common-question-evidence-status.md`. For coverage auditing across the whole docs objective, use `common-question-coverage-map.md`. These are answer patterns, not final proof. For fragile platform behavior, follow the linked source docs before making a hard claim. +Use this page when an AI agent needs a short, practical answer to a common SSN support question. For first-stop routing by user intent, start with `question-intent-router.md` or `docs/agents/11-support-kb/index.md`. For a compact "answer shape, must-check, do-not-say" matrix, use `common-question-fast-path.md`. For command/option/setting/mode confusion, use `../13-reference/control-surface-crosswalk.md`. For paraphrased real-world wording patterns, use `support-question-phrasebook.md`. For ready-to-send support templates, use `support-response-playbook.md`. For SSN-filtered macro-style replies from curated support playbooks, use `support-macro-routing.md`. For evidence-strength and runtime-proof status, use `common-question-evidence-status.md`. For what proof is required before stronger answers, use `common-question-proof-pack.md`. For coverage auditing across the whole docs objective, use `common-question-coverage-map.md`. These are answer patterns, not final proof. For fragile platform behavior, follow the linked source docs before making a hard claim. ## Ground Rules For Answers diff --git a/docs/agents/13-reference/index.md b/docs/agents/13-reference/index.md index cd9d3d108..00dad1602 100644 --- a/docs/agents/13-reference/index.md +++ b/docs/agents/13-reference/index.md @@ -67,6 +67,7 @@ Use these pages when the user asks "how do I do X?" and the answer may involve m - `11-support-kb/support-question-phrasebook.md`: paraphrased support-history wording patterns tied to canonical docs and safe answer boundaries. - `11-support-kb/common-question-coverage-map.md`: objective-level map of common question families to current docs and validation gaps. - `11-support-kb/common-question-evidence-status.md`: evidence-strength and runtime-proof status for common SSN answer families. +- `11-support-kb/common-question-proof-pack.md`: evidence artifacts required before stronger answers about commands, options, supported sites, modes, customization, costs, privacy, testing, and platform behavior. - `15-objective-coverage-and-readiness-audit.md`: objective requirement coverage, answer-readiness labels, completion evidence, and remaining proof gaps. - `16-runtime-validation-playbooks.md`: runtime validation recipes and evidence templates for final-grade command, option, source, app, OBS, integration, AI/TTS, and support-claim evidence. - `18-focused-validation-evidence-log.md`: focused non-runtime validation evidence, currently including settings config JSON, generated settings/URL/public-site metadata checks, Event Flow, Twitch provider, AI prompt builder, AI moderation, local model registry, provider fallback, local TTS, local AI asset, and RAG fixture tests. diff --git a/docs/agents/14-validation-and-refresh-roadmap.md b/docs/agents/14-validation-and-refresh-roadmap.md index 7d810041c..c0d731854 100644 --- a/docs/agents/14-validation-and-refresh-roadmap.md +++ b/docs/agents/14-validation-and-refresh-roadmap.md @@ -27,7 +27,7 @@ Current overlay runtime notes: `scoreboard.html` and `reactions.html` have narro Current focused validation notes: Event Flow custom JS, compare-property, template/counter, OBS system trigger, and play-media duration Node tests have focused evidence in `18-focused-validation-evidence-log.md`. Twitch subgift provider normalization, AI prompt builder smoke behavior, profanity/moderation static checks, local browser model registry checks, OpenCode Zen fallback checks, Kokoro asset wiring, Kitten TTS asset wiring, Transformers local defaults, RAG browser-fixture/benchmark behavior, settings config JSON validation, generated settings/URL/public-site metadata validation, and API command examples documentation consistency also have focused evidence there. Piper asset wiring has a failed focused test on an expected fallback remote-base string. The generated metadata check completed with duplicate URL alias findings for `password` and normalized `strokecolor`, plus duplicate public `On24`/`ON24` cards. The API examples consistency check found 29 extracted action examples and, after docs updates, zero missing entries across action index, validation matrix, and source trace, but it does not validate command behavior. These results do not validate Event Flow UI, Flow Actions overlay, OBS, app, extension, live platform behavior, browser audio, model runtime, real RAG uploads, live moderation quality, live LLM generation, generated overlay quality, provider calls, provider availability/pricing, popup/settings UI, generated docs UI, page-specific URL parsing, public supported-sites UI, API relay behavior, action callbacks, target labels, numbered content channels, or external integration behavior. -Current docs-navigation note: `19-navigation-and-link-audit.md` records a focused agent-doc navigation audit. The latest result found 163 Markdown files, zero unreferenced non-template pages, zero broken exact agent-doc Markdown references, and zero ambiguous bare section-index filenames. Re-run it after large documentation-growth, rename, or section-index changes. +Current docs-navigation note: `19-navigation-and-link-audit.md` records a focused agent-doc navigation audit. The latest result found 164 Markdown files, zero unreferenced non-template pages, zero broken exact agent-doc Markdown references, and zero ambiguous bare section-index filenames. Re-run it after large documentation-growth, rename, or section-index changes. ## Priority Queue diff --git a/docs/agents/15-objective-coverage-and-readiness-audit.md b/docs/agents/15-objective-coverage-and-readiness-audit.md index e5dee6978..96f5afa44 100644 --- a/docs/agents/15-objective-coverage-and-readiness-audit.md +++ b/docs/agents/15-objective-coverage-and-readiness-audit.md @@ -37,8 +37,8 @@ Steve asked for comprehensive AI-focused documentation around: | --- | --- | --- | --- | | Agent workspace scope and rules | `AGENT.md`, `00-inventory-and-plan.md` | covered-heavy | Keep updated if write boundary or source priority changes. | | Resource inventory and extraction checklist | `02-resource-manifest.md`, `01-extraction-checklist.md`, `02-resource-processing-ledger.md` | covered-heavy | Continue adding pass rows after every new extraction/validation pass. | -| Agent-doc navigation and link hygiene | `docs/index.html`, `docs/agents/SITEMAP.md`, section `docs/agents/*/SITEMAP.md` files, `99-agent-index.md`, `AGENT.md`, `19-navigation-and-link-audit.md`, section indexes | covered-quick plus focused docs audit plus static viewer/sitemaps | Current audit covers 163 Markdown files with zero unreferenced non-template pages, zero broken exact agent-doc Markdown refs, and zero ambiguous bare section-index filenames. Browser smoke passed for default doc load, deep link load, section sitemap link traversal, raw link state, sidebar filter, and zero console errors. Re-run after major page additions, renames, or section index changes; current audit does not validate external/source links or all rendered anchors. | -| Common question routing and evidence status | `11-support-kb/question-intent-router.md`, `11-support-kb/common-question-fast-path.md`, `11-support-kb/common-question-evidence-status.md`, `11-support-kb/common-question-test-set.md`, `11-support-kb/support-question-phrasebook.md`, `11-support-kb/common-question-coverage-map.md` | covered-heavy plus prompt benchmark | Add new paraphrased support wording after future QA exports and add runtime evidence only after actual validation. Use the test set to check common prompt routing and safe-answer behavior. | +| Agent-doc navigation and link hygiene | `docs/index.html`, `docs/agents/SITEMAP.md`, section `docs/agents/*/SITEMAP.md` files, `99-agent-index.md`, `AGENT.md`, `19-navigation-and-link-audit.md`, section indexes | covered-quick plus focused docs audit plus static viewer/sitemaps | Current audit covers 164 Markdown files with zero unreferenced non-template pages, zero broken exact agent-doc Markdown refs, and zero ambiguous bare section-index filenames. Browser smoke passed for default doc load, deep link load, section sitemap link traversal, raw link state, sidebar filter, and zero console errors. Re-run after major page additions, renames, or section index changes; current audit does not validate external/source links or all rendered anchors. | +| Common question routing and evidence status | `11-support-kb/question-intent-router.md`, `11-support-kb/common-question-fast-path.md`, `11-support-kb/common-question-evidence-status.md`, `11-support-kb/common-question-proof-pack.md`, `11-support-kb/common-question-test-set.md`, `11-support-kb/support-question-phrasebook.md`, `11-support-kb/common-question-coverage-map.md` | covered-heavy plus prompt benchmark | Add new paraphrased support wording after future QA exports and add runtime evidence only after actual validation. Use the proof pack before stronger claims and the test set to check common prompt routing and safe-answer behavior. | | Short support answers and response phrasing | `11-support-kb/support-answer-bank.md`, `support-response-playbook.md`, `support-macro-routing.md`, `support-intake-templates.md` | covered-heavy | Source-check fragile platform claims before sending final answers. | | Support-history evidence and stale-claim handling | `11-support-kb/mining-method.md`, `support-history-refresh-playbook.md`, `support-topic-frequency-index.md`, `historical-issues.md`, `support-evidence-ledger.md`, `unresolved-or-stale-claims.md`, `stevesbot-resource-inventory.md` | covered-heavy/frequency-pass plus repeatable refresh workflow | Promote or reject historical claims only after current source or runtime validation. Use the refresh playbook to rerun aggregate support-history counts without leaking raw support data. | | Product overview and install surfaces | `01-product-map.md`, `02-installation-and-surfaces.md`, `13-reference/install-update-version-guide.md` | covered-heavy | Reconcile exact release/version/update behavior before public final docs. | @@ -85,7 +85,8 @@ Most current docs are `answer-ready orientation`, `source-backed`, `generated in | --- | --- | --- | | "What is SSN?" | answer-ready orientation | Answer directly from product/support docs. | | "What is the fastest safe answer path for a common question?" | answer-ready orientation | Start with `common-question-fast-path.md`, then open the routed proof docs before exact claims. | -| "How strong is the evidence for this common answer?" | answer-ready orientation | Start with `common-question-evidence-status.md`, then inspect routed docs and runtime evidence before stronger wording. | +| "How strong is the evidence for this common answer?" | answer-ready orientation | Start with `common-question-evidence-status.md`, then inspect `common-question-proof-pack.md`, routed docs, and runtime evidence before stronger wording. | +| "What proof is needed before a stronger answer?" | answer-ready orientation | Start with `common-question-proof-pack.md`, then gather the exact source/config/focused/runtime evidence required by the question family. | | "Which support macro should I use?" | answer-ready orientation | Start with `support-macro-routing.md`, then source-check the routed topic docs before exact platform or app claims. | | "Is SSN free?" | answer-ready orientation | Say SSN is free/open source; third-party providers/platforms can cost money. | | "Can I repeat the public 100+/120+/two-way/no-API-key claim?" | answer-ready orientation | Use `public-claims-boundary-matrix.md`; narrow by platform, mode, provider, and validation level. | @@ -120,7 +121,7 @@ The documentation objective should not be marked complete until current evidence 9. Runtime-tested claims have actual runtime evidence, not only static/source inspection. 10. Docs-only validation passes and no files outside the approved docs scope, `docs/index.html` plus `docs/agents`, were changed for the documentation work. -Items 1 through 8 are mostly covered. Item 6 now has focused docs-navigation audit support from `19-navigation-and-link-audit.md`, which found zero unreferenced non-template Markdown pages, zero broken exact agent-doc Markdown references, and zero ambiguous bare section-index filenames across 163 Markdown files. Items 9 and 10 must be rechecked at the end of every continuation. Item 9 remains the largest reason not to mark the full objective complete. +Items 1 through 8 are mostly covered. Item 6 now has focused docs-navigation audit support from `19-navigation-and-link-audit.md`, which found zero unreferenced non-template Markdown pages, zero broken exact agent-doc Markdown references, and zero ambiguous bare section-index filenames across 164 Markdown files. Items 9 and 10 must be rechecked at the end of every continuation. Item 9 remains the largest reason not to mark the full objective complete. Current runtime evidence is partial. As of 2026-06-24, `17-runtime-validation-evidence-log.md` records controlled local browser validation for `scoreboard.html` preview/local scoring behavior and `reactions.html` popup URL parsing, synthetic bridge/payload rendering, fake server-mode joins, and controlled TikTok-like target routing. It also records a failed `multi-alerts.html` validation attempt that timed out waiting for the preview iframe overlay API. This evidence does not validate OBS, hosted pages, the real extension/app bridge, live platform/source payloads, real WebSocket relay delivery, labels/password/session behavior outside the tested URLs, or long-running persistence. diff --git a/docs/agents/19-navigation-and-link-audit.md b/docs/agents/19-navigation-and-link-audit.md index 4cf0c38e1..70f2fdabe 100644 --- a/docs/agents/19-navigation-and-link-audit.md +++ b/docs/agents/19-navigation-and-link-audit.md @@ -30,7 +30,7 @@ Not audited as broken links: Read-only inline Node audit result: ```text -totalMarkdown: 163 +totalMarkdown: 164 orphanishCount: 0 localBrokenCount: 0 ambiguousBareSectionIndexCount: 0 diff --git a/docs/agents/99-agent-index.md b/docs/agents/99-agent-index.md index 90fe20189..ea551eb93 100644 --- a/docs/agents/99-agent-index.md +++ b/docs/agents/99-agent-index.md @@ -1,6 +1,6 @@ # SSN AI Documentation Index -Status: framework plus source-backed backbone, product/install, install/update/version, standalone app source-window parity, overlays, theme pages, individual game pages, tip jar/credits, AI/cohost pages, event/effect overlays, live display utilities, specialized/legacy pages, diagnostic/helper pages, page capability routing, page processing inventory, API/integrations, common FAQ, common question intent router, common question fast path, common question evidence status, common question test set, support question phrasebook, support macro routing, common question coverage map, objective coverage/readiness audit, common misconceptions/boundaries, public claims boundary matrix, diagnostic decision tree, workflow setup decision tree, validation/refresh roadmap, runtime validation playbook, runtime evidence log, focused validation evidence log, navigation/link audit, support KB index, support evidence ledger, support history refresh playbook, support topic frequency index, support response playbook, support intake templates, support answer bank, privacy/security, custom-source, customization path decision matrix, customization source trace, troubleshooting, priority platform answer and validation ledgers, TikTok standalone app connector, remaining platform source, static/manual/helper sources, WebSocket/API source pages, communication/sensitive source scripts, embedded chat widget sources, live-commerce source scripts, webinar/event source scripts, creator-live-cam source scripts, popout/chat-only source scripts, event/community source scripts, independent live platform source scripts, video/broadcast platform source scripts, community/membership web-app source scripts, regional/emerging platform source scripts, special-case platform/helper source scripts, supported-site lookup/status/implementation map, source-file matrix, manifest row matrix, manifest source-load, platform capability matrix, Event Flow/Streamer.bot, first support-mining, desktop-app support, development/provider/test-asset, reference, control-surface crosswalk, action lookup, command source trace, API command validation matrix, API examples, URL option examples, URL parameter source trace, root page URL parameter matrix, subpage URL parameter matrix, settings, settings/session/storage source trace, settings change impact matrix, feature decision matrix, exact generated lookup, glossary, surface URL routing, how-to recipe, and preflight checklist passes. +Status: framework plus source-backed backbone, product/install, install/update/version, standalone app source-window parity, overlays, theme pages, individual game pages, tip jar/credits, AI/cohost pages, event/effect overlays, live display utilities, specialized/legacy pages, diagnostic/helper pages, page capability routing, page processing inventory, API/integrations, common FAQ, common question intent router, common question fast path, common question evidence status, common question proof pack, common question test set, support question phrasebook, support macro routing, common question coverage map, objective coverage/readiness audit, common misconceptions/boundaries, public claims boundary matrix, diagnostic decision tree, workflow setup decision tree, validation/refresh roadmap, runtime validation playbook, runtime evidence log, focused validation evidence log, navigation/link audit, support KB index, support evidence ledger, support history refresh playbook, support topic frequency index, support response playbook, support intake templates, support answer bank, privacy/security, custom-source, customization path decision matrix, customization source trace, troubleshooting, priority platform answer and validation ledgers, TikTok standalone app connector, remaining platform source, static/manual/helper sources, WebSocket/API source pages, communication/sensitive source scripts, embedded chat widget sources, live-commerce source scripts, webinar/event source scripts, creator-live-cam source scripts, popout/chat-only source scripts, event/community source scripts, independent live platform source scripts, video/broadcast platform source scripts, community/membership web-app source scripts, regional/emerging platform source scripts, special-case platform/helper source scripts, supported-site lookup/status/implementation map, source-file matrix, manifest row matrix, manifest source-load, platform capability matrix, Event Flow/Streamer.bot, first support-mining, desktop-app support, development/provider/test-asset, reference, control-surface crosswalk, action lookup, command source trace, API command validation matrix, API examples, URL option examples, URL parameter source trace, root page URL parameter matrix, subpage URL parameter matrix, settings, settings/session/storage source trace, settings change impact matrix, feature decision matrix, exact generated lookup, glossary, surface URL routing, how-to recipe, and preflight checklist passes. ## Start Here @@ -15,7 +15,7 @@ Status: framework plus source-backed backbone, product/install, install/update/v - `16-runtime-validation-playbooks.md`: concrete runtime validation recipes and evidence templates for final-grade command, option, source, app, OBS, integration, AI/TTS, and support-claim validation. - `17-runtime-validation-evidence-log.md`: actual runtime validation evidence entries; currently includes controlled browser validation for `scoreboard.html` and `reactions.html`, plus a failed `multi-alerts.html` validation attempt. - `18-focused-validation-evidence-log.md`: focused validation evidence that is useful but not full runtime testing; currently includes settings config JSON, generated settings/URL/public-site metadata checks, Event Flow, Twitch provider, AI prompt builder, AI moderation, local model registry, provider fallback, local TTS, local AI asset, RAG fixture tests, and API command examples documentation consistency. -- `19-navigation-and-link-audit.md`: documentation navigation/link audit; current result is 163 Markdown files, zero unreferenced non-template pages, zero broken exact agent-doc Markdown references, and zero ambiguous bare section-index filenames. +- `19-navigation-and-link-audit.md`: documentation navigation/link audit; current result is 164 Markdown files, zero unreferenced non-template pages, zero broken exact agent-doc Markdown references, and zero ambiguous bare section-index filenames. ## Core Topic Pages @@ -37,6 +37,7 @@ Status: framework plus source-backed backbone, product/install, install/update/v - `11-support-kb/question-intent-router.md`: plain-language user wording to canonical doc route, first disambiguation question, and wrong-route warnings. - `11-support-kb/common-question-fast-path.md`: compact common-question matrix with fast answer shape, required checks, overclaims to avoid, and proof docs. - `11-support-kb/common-question-evidence-status.md`: evidence-strength and runtime-proof status by common SSN answer family. +- `11-support-kb/common-question-proof-pack.md`: proof artifacts required before stronger answers about commands, options, supported sites, modes, customization, costs, privacy, testing, and platform behavior. - `11-support-kb/common-question-test-set.md`: benchmark-style common prompt set with expected doc routes, required caveats, and fail conditions for agent answer checks. - `11-support-kb/support-question-phrasebook.md`: paraphrased support-history wording patterns tied to canonical docs and safe answer boundaries. - `11-support-kb/support-macro-routing.md`: SSN-filtered support macros from curated support playbooks for safe intake, overlay blank, TikTok, Twitch auth, platform-change, API no-op, app, AI/TTS, plugin, and escalation routing. diff --git a/docs/agents/AGENT.md b/docs/agents/AGENT.md index f844af33d..90958abeb 100644 --- a/docs/agents/AGENT.md +++ b/docs/agents/AGENT.md @@ -80,6 +80,7 @@ For support-style answers: - `docs/agents/11-support-kb/question-intent-router.md`: plain-language user wording to canonical doc route, first disambiguation question, and wrong-route warnings. - `docs/agents/11-support-kb/common-question-fast-path.md`: compact answer-shape matrix for common questions, with required checks and overclaims to avoid. - `docs/agents/11-support-kb/common-question-evidence-status.md`: evidence-strength and runtime-proof status for common answer families. +- `docs/agents/11-support-kb/common-question-proof-pack.md`: proof artifacts required before stronger answers about commands, options, supported sites, modes, customization, costs, privacy, testing, and platform behavior. - `docs/agents/11-support-kb/common-question-test-set.md`: benchmark-style prompt set for testing common-question routing and safe-answer behavior. - `docs/agents/11-support-kb/support-question-phrasebook.md`: paraphrased support-history wording patterns tied to canonical docs and safe answer boundaries. - `docs/agents/11-support-kb/support-macro-routing.md`: SSN-filtered support macros from curated support playbooks for safe intake, common short replies, and escalation routing. @@ -129,7 +130,7 @@ For feature-specific answers: 1. Identify the user's intent: setup, troubleshooting, capability check, platform-specific behavior, commands/API, customization, app behavior, or development. 2. Start from the matching router: support KB index, workflow setup decision tree, diagnostic decision tree, platform index, overlay index, API/integration index, or development index. 3. Read the exact topic page before answering. Do not answer from the index alone for fragile claims. -4. Check `common-misconceptions-and-boundaries.md`, `public-claims-boundary-matrix.md`, `support-evidence-ledger.md`, and `common-question-evidence-status.md` before making broad claims about supported sites, app parity, send-back, costs, privacy, support, services, or testing. +4. Check `common-misconceptions-and-boundaries.md`, `public-claims-boundary-matrix.md`, `support-evidence-ledger.md`, `common-question-evidence-status.md`, and `common-question-proof-pack.md` before making broad or stronger claims about supported sites, app parity, send-back, costs, privacy, support, services, or testing. 5. Use `support-macro-routing.md` for short support-thread macros and `support-response-playbook.md` for fuller user-facing phrasing when the answer resembles a support reply. 6. Inspect current source code before presenting high-risk or final-grade claims about selectors, auth flows, command payloads, send-back, settings persistence, source windows, app parity, or rendered overlay behavior. From 4de96c98fae57ed00a433177388b825948cf5810 Mon Sep 17 00:00:00 2001 From: steveseguin Date: Wed, 24 Jun 2026 08:21:19 -0400 Subject: [PATCH 25/30] fix(xss): harden basic HTML filter probes - Add regex filters in `filterXSS` to block event handlers (e.g., `onclick=`, `onerror=`), `javascript:` URIs, the `srcdoc` attribute, and `data:` URIs (including `data:text/html`) - Extend the WebSocket test source with false-positive test scenarios that verify safe mentions of XSS-related terms are not blocked - Strengthen initial probe detection while preserving legitimate message content [auto-enhanced] --- libs/objects.js | 5 ++++ sources/websocket/testsource.html | 40 +++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/libs/objects.js b/libs/objects.js index 0e5babb1f..6b395624e 100644 --- a/libs/objects.js +++ b/libs/objects.js @@ -16,6 +16,11 @@ function filterXSS(unsafe) { // this is not foolproof, but it might catch some basic probe attacks that sneak in try { return unsafe + .replace(/[\s\/]on[a-z0-9_-]+\s*=/gi, " data-blocked-event=") + .replace(/javascript\s*:/gi, "**") + .replace(/srcdoc\s*=/gi, "**") + .replace(/src\s*=\s*["']?\s*data\s*:[^"'\s>]*/gi, 'src=""') + .replace(/data\s*:\s*text\/html/gi, "**") .replaceAll("prompt(", "**") .replaceAll("eval(", "**") .replaceAll("onclick(", "**") diff --git a/sources/websocket/testsource.html b/sources/websocket/testsource.html index 194dad696..96c6bd2cc 100644 --- a/sources/websocket/testsource.html +++ b/sources/websocket/testsource.html @@ -197,6 +197,46 @@

Social Stream Test Source

title: "same raw payload with textonly", message: "", textonly: true + }, + { + title: "false positive: alert function discussion", + message: "Can someone explain why alert('hi') freezes the overlay?", + textonly: false + }, + { + title: "false positive: javascript label", + message: "The docs say JavaScript: the language has weird edge cases.", + textonly: false + }, + { + title: "false positive: innerHTML discussion", + message: "I think innerHTML is the risky part here.", + textonly: false + }, + { + title: "false positive: event attribute docs", + message: "The article mentioned onerror= and onload= attributes.", + textonly: false + }, + { + title: "false positive: srcdoc docs", + message: "iframe srcdoc= is useful in examples but should be handled carefully.", + textonly: false + }, + { + title: "false positive: data html mime type", + message: "data:text/html is a MIME type people mention in CSP discussions.", + textonly: false + }, + { + title: "false positive: write function text", + message: "Old tutorials used document.write('hello') and write('hello').", + textonly: false + }, + { + title: "false positive: script tag discussion", + message: "If you type

hasDonation Facebook Stars rendered in the Live Chat DOM.Standard chat payload; hasDonation carries the visible Stars amount, such as 100 Stars. Stars do not set data.event.Standard chat payload; hasDonation carries the visible Stars amount, such as 100 Stars, and donoValue carries the USD value. Stars do not set data.event.
highlightColor