Uploaded the Tampermonkey Harness

This commit is contained in:
0% [█ █ █ █ █ █ █ █ █ █] 100% 2026-06-04 20:37:32 -05:00
parent ace1e61285
commit 86515e46dd
2 changed files with 929 additions and 1 deletions

View File

@ -0,0 +1,928 @@
// ==UserScript==
// @name Unified AI C2 Harness
// @namespace http://tampermonkey.net/
// @version 1.3
// @description Unified C2 harness for Google AI Search, ChatGPT, DeepSeek, and Google Gemini.
// @author Vanguard
// @match https://*.google.com/*
// @match http://*.google.com/*
// @match https://chatgpt.com/*
// @match https://chat.openai.com/*
// @match https://chat.deepseek.com/*
// @match https://gemini.google.com/*
// @connect localhost
// @connect 127.0.0.1
// @grant GM_xmlhttpRequest
// @run-at document-idle
// ==/UserScript==
(function() {
'use strict';
if (window.top !== window.self) {
return;
}
const hostname = window.location.hostname;
let currentPlatform = null;
if (hostname.includes('chatgpt.com') || hostname.includes('chat.openai.com')) {
currentPlatform = 'ChatGPT';
} else if (hostname.includes('chat.deepseek.com')) {
currentPlatform = 'DeepSeek';
} else if (hostname.includes('gemini.google.com')) {
currentPlatform = 'Gemini';
} else if (hostname.includes('google.com')) {
currentPlatform = 'Google';
} else {
return; // Not a supported platform
}
console.log(`[Harness] Initializing Unified Harness for ${currentPlatform}...`);
const API_BASE = "http://localhost:8080/api/relay";
const POLLING_INTERVAL = 1000;
const STATE_INTERVAL = 2000;
let isBusy = false;
let isPolling = false;
let pollIntervalId = null;
let stateIntervalId = null;
let PLATFORM_NAME = "";
let ID_PREFIX = "";
let activeActions = {};
let activeTactics = null;
let reportStateLogic = null;
// --- TAMPERMONKEY FETCH WRAPPER (CORS BYPASS) ---
function tmFetch(url, options = {}) {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: options.method || 'GET',
url: url,
headers: options.headers || {},
data: options.body,
onload: function(response) {
resolve({
status: response.status,
json: () => {
try {
return Promise.resolve(JSON.parse(response.responseText));
} catch (e) {
return Promise.resolve({});
}
},
text: () => Promise.resolve(response.responseText)
});
},
onerror: function(error) {
reject(error);
}
});
});
}
// --- DOM TACTICS ---
const standardTactics = {
setNativeValue: (element, value) => {
element.focus();
let success = false;
try { success = document.execCommand('insertText', false, value); } catch (e) {}
if (!success) {
const valueSetter = Object.getOwnPropertyDescriptor(element, 'value')?.set;
const prototype = Object.getPrototypeOf(element);
const prototypeValueSetter = Object.getOwnPropertyDescriptor(prototype, 'value')?.set;
if (prototypeValueSetter && valueSetter !== prototypeValueSetter) {
prototypeValueSetter.call(element, value);
} else if (valueSetter) {
valueSetter.call(element, value);
} else {
element.value = value;
}
}
element.dispatchEvent(new Event('input', { bubbles: true }));
element.dispatchEvent(new Event('change', { bubbles: true }));
}
};
const contentEditableTactics = {
setNativeValue: (element, value) => {
element.focus();
// Safely select only the contents of the target element
const selection = window.getSelection();
const range = document.createRange();
range.selectNodeContents(element);
selection.removeAllRanges();
selection.addRange(range);
try {
document.execCommand('delete', false, null);
document.execCommand('insertText', false, value);
} catch (e) {
console.error("[Harness] execCommand failed, falling back to textContent", e);
element.textContent = value;
}
element.dispatchEvent(new Event('input', { bubbles: true }));
element.dispatchEvent(new Event('change', { bubbles: true }));
}
};
// --- SMART EXTRACTION (Markdown Parsers) ---
function googleHtmlToMarkdown(node) {
if (node.nodeType === Node.TEXT_NODE) return node.textContent;
if (node.nodeType !== Node.ELEMENT_NODE) return "";
const tag = node.tagName.toUpperCase();
if (tag === 'BUTTON' || tag === 'SVG' || tag === 'STYLE' || tag === 'SCRIPT' || tag === 'NOSCRIPT') return "";
if (node.style && node.style.display === 'none') return "";
if (node.getAttribute('aria-hidden') === 'true') return "";
if (node.classList) {
if (node.classList.contains('DHPVt') || node.classList.contains('YHsVn') || node.classList.contains('bQ0Yzc') || node.classList.contains('CxFouc') || node.classList.contains('ZFcyjd') || node.classList.contains('lHqILb')) return "";
}
if (node.hasAttribute('data-xpm-latex')) return node.getAttribute('data-xpm-latex');
if (tag === 'PRE') return `\n\n\`\`\`\n${node.textContent}\n\`\`\`\n\n`;
if (tag === 'BR') return '\n';
let md = "";
for (let child of node.childNodes) md += googleHtmlToMarkdown(child);
if (tag === 'P' || tag === 'DIV') {
const displayStyle = node.style ? node.style.display : '';
if (displayStyle.includes('inline')) return md;
return `\n\n${md}\n\n`;
}
if (tag === 'STRONG' || tag === 'B') return `**${md}**`;
if (tag === 'EM' || tag === 'I') return `*${md}*`;
if (tag === 'CODE') return `\`${md}\``;
if (tag.match(/^H[1-6]$/)) return `\n\n${'#'.repeat(parseInt(tag[1]))} ${md}\n\n`;
if (tag === 'LI') return `\n- ${md.trim()}`;
if (tag === 'UL' || tag === 'OL') return `\n${md}\n`;
if (tag === 'A') return `[${md}](${node.getAttribute('href') || ''})`;
return md;
}
function chatgptHtmlToMarkdown(node) {
if (node.nodeType === Node.TEXT_NODE) return node.textContent;
if (node.nodeType !== Node.ELEMENT_NODE) return "";
const tag = node.tagName.toUpperCase();
if (tag === 'BUTTON' || tag === 'SVG' || tag === 'STYLE' || tag === 'SCRIPT' || tag === 'NOSCRIPT') return "";
if (node.style && node.style.display === 'none') return "";
if (node.getAttribute('aria-hidden') === 'true') return "";
if (tag === 'PRE') {
const codeNode = node.querySelector('code');
const codeText = codeNode ? codeNode.textContent : node.textContent;
return `\n\n\`\`\`\n${codeText}\n\`\`\`\n\n`;
}
if (tag === 'BR') return '\n';
let md = "";
for (let child of node.childNodes) md += chatgptHtmlToMarkdown(child);
if (tag === 'P' || tag === 'DIV') return `\n\n${md}\n\n`;
if (tag === 'STRONG' || tag === 'B') return `**${md}**`;
if (tag === 'EM' || tag === 'I') return `*${md}*`;
if (tag === 'CODE') return `\`${md}\``;
if (tag.match(/^H[1-6]$/)) return `\n\n${'#'.repeat(parseInt(tag[1]))} ${md}\n\n`;
if (tag === 'LI') return `\n- ${md.trim()}`;
if (tag === 'UL' || tag === 'OL') return `\n${md}\n`;
if (tag === 'A') {
const href = node.getAttribute('href') || '';
const cleanMd = md.trim();
if (cleanMd && (href.includes(cleanMd) || cleanMd.includes(href))) return md;
return `[${md}](${href})`;
}
return md;
}
function deepseekHtmlToMarkdown(node) {
if (node.nodeType === Node.TEXT_NODE) return node.textContent;
if (node.nodeType !== Node.ELEMENT_NODE) return "";
const tag = node.tagName.toUpperCase();
if (tag === 'BUTTON' || tag === 'SVG' || tag === 'STYLE' || tag === 'SCRIPT' || tag === 'NOSCRIPT') return "";
if (node.style && node.style.display === 'none') return "";
if (node.getAttribute('aria-hidden') === 'true') return "";
if (tag === 'PRE') return `\n\n\`\`\`\n${node.textContent}\n\`\`\`\n\n`;
if (tag === 'BR') return '\n';
let md = "";
for (let child of node.childNodes) md += deepseekHtmlToMarkdown(child);
if (tag === 'P' || tag === 'DIV') return `\n\n${md}\n\n`;
if (tag === 'STRONG' || tag === 'B') return `**${md}**`;
if (tag === 'EM' || tag === 'I') return `*${md}*`;
if (tag === 'CODE') return `\`${md}\``;
if (tag.match(/^H[1-6]$/)) return `\n\n${'#'.repeat(parseInt(tag[1]))} ${md}\n\n`;
if (tag === 'LI') return `\n- ${md.trim()}`;
if (tag === 'UL' || tag === 'OL') return `\n${md}\n`;
if (tag === 'A') {
const href = node.getAttribute('href') || '';
const cleanMd = md.trim();
if (cleanMd && (href.includes(cleanMd) || cleanMd.includes(href))) return md;
return `[${md}](${href})`;
}
return md;
}
// --- ACTION MODULES ---
const googleActions = {
SHUTDOWN: async () => {
clearInterval(pollIntervalId);
clearInterval(stateIntervalId);
console.log("[Harness] Shutdown command received. Loops stopped.");
return "Harness shut down.";
},
GENERATE: async (payload) => {
const textareas = Array.from(document.querySelectorAll('textarea')).filter(el => el.offsetWidth > 0 && el.offsetHeight > 0);
let input = textareas[textareas.length - 1];
if (!input) input = document.querySelector('input[name="q"]');
if (!input) return "Error: Prompt textarea not found on this Google page. SGE may not be active.";
const preSubmitParagraphs = document.querySelectorAll('.n6owBd');
let preSubmitText = "";
let preSubmitNoResponseEl = null;
const noRespSelector = '.Y3BBE, .luHWlf, [data-sfc-root], [jscontroller="zcfIf"]';
if (preSubmitParagraphs.length > 0) {
preSubmitText = preSubmitParagraphs[preSubmitParagraphs.length - 1].parentElement.innerText || "";
} else {
const noRespNodes = document.querySelectorAll(noRespSelector);
for (let n of noRespNodes) {
if (n.innerText && n.innerText.includes("no response available")) {
preSubmitText = n.innerText;
preSubmitNoResponseEl = n;
break;
}
}
}
standardTactics.setNativeValue(input, payload);
await new Promise(r => setTimeout(r, 800));
const submitSelectors = ['button.SAvKK', 'button.qmJOdc', 'button[aria-label="Submit"]', 'button[aria-label="Search"]'];
let runBtn = null;
for(let sel of submitSelectors) {
const btns = Array.from(document.querySelectorAll(sel)).filter(b => b.offsetWidth > 0);
for(let btn of btns) {
if(!btn.disabled && btn.getAttribute('aria-disabled') !== 'true') {
runBtn = btn;
break;
}
}
if(runBtn) break;
}
if (runBtn) {
runBtn.click();
} else {
console.log("[Harness] Submit button not found or disabled, dispatching Enter key fallback...");
const enterEvent = new KeyboardEvent('keydown', { bubbles: true, cancelable: true, key: 'Enter', code: 'Enter', keyCode: 13 });
input.dispatchEvent(enterEvent);
}
console.log("[Harness] Command sent. Entering Kinetic Wait (2500ms)...");
await new Promise(r => setTimeout(r, 2500));
console.log("[Harness] Wait complete. Engaging Semantic Lock...");
return new Promise((resolve) => {
let lastTextLength = -1;
let stabilityStreak = 0;
const REQUIRED_STREAK = 1;
let maxWait = 180;
let isNewResponseStarted = false;
const checkLoop = setInterval(() => {
maxWait--;
if (maxWait <= 0) {
clearInterval(checkLoop);
resolve("Error: Generation timed out or hung.");
return;
}
const noResponseNodes = document.querySelectorAll(noRespSelector);
let currentNoResponseEl = null;
let currentNoResponseText = "";
for (let node of noResponseNodes) {
if (node.innerText && node.innerText.includes("no response available")) {
currentNoResponseEl = node;
currentNoResponseText = node.innerText;
break;
}
}
if (currentNoResponseEl) {
if (!isNewResponseStarted) {
if (currentNoResponseText !== preSubmitText || currentNoResponseEl !== preSubmitNoResponseEl) {
isNewResponseStarted = true;
console.log("[Harness] Detected new 'no response' stream starting.");
} else {
console.log("[Harness] Waiting for old 'no response' to clear/change...");
return;
}
}
if (isNewResponseStarted) {
clearInterval(checkLoop);
console.log("[Harness] Detected 'no response available' message. Returning empty response.");
resolve("");
return;
}
}
const paragraphs = document.querySelectorAll('.n6owBd');
if (paragraphs.length === 0) {
console.log("[Harness] Waiting for SGE turn container...");
return;
}
const lastTurnContainer = paragraphs[paragraphs.length - 1].parentElement;
const currentTextContent = lastTurnContainer.innerText || "";
const currentTextLength = currentTextContent.length;
if (!isNewResponseStarted) {
if (currentTextContent !== preSubmitText || currentTextContent === "" || currentTextLength < preSubmitText.length) {
isNewResponseStarted = true;
console.log("[Harness] Detected new response stream starting.");
} else {
console.log("[Harness] Waiting for old response to clear/change...");
return;
}
}
const isTextGrowing = currentTextLength > lastTextLength;
if (isTextGrowing) {
console.log(`[Harness] Status: Streaming... (+${currentTextLength - lastTextLength})`);
lastTextLength = currentTextLength;
stabilityStreak = 0;
} else if (currentTextLength === 0) {
console.log(`[Harness] Status: Waiting for text generation to begin...`);
stabilityStreak = 0;
} else {
stabilityStreak++;
console.log(`[Harness] Status: Stable... (${stabilityStreak}/${REQUIRED_STREAK})`);
lastTextLength = currentTextLength;
}
if (stabilityStreak >= REQUIRED_STREAK) {
clearInterval(checkLoop);
console.log("[Harness] Lock Released. Extraction initiated.");
let turnMd = googleHtmlToMarkdown(lastTurnContainer);
turnMd = turnMd.replace(/\n{3,}/g, '\n\n').trim();
resolve(turnMd);
}
}, 1000);
});
},
NEW_CHAT: async () => {
const newThreadBtn = document.querySelector('button[aria-label="New thread"]') || document.querySelector('.cV1Mfc');
if (newThreadBtn) {
newThreadBtn.click();
return "Chat reset.";
}
return "Error: New thread button not found.";
},
GET_CHAT_HISTORY: async () => {
const history = [];
const turns = document.querySelectorAll('.VndcI, .n6owBd');
turns.forEach(turn => {
if (turn.classList.contains('VndcI')) {
let text = turn.innerText.replace('You said:', '').trim();
if (text) history.push({ role: "User", text: text });
} else if (turn.classList.contains('n6owBd')) {
let text = googleHtmlToMarkdown(turn).trim();
if (text) history.push({ role: "Model", text: text });
}
});
return JSON.stringify(history);
},
ANALYZE_SESSION: async () => {
return JSON.stringify({
isHydrated: document.querySelectorAll('.n6owBd').length > 0,
turnCount: document.querySelectorAll('.n6owBd').length,
url: window.location.href
});
},
GET_SETTINGS: async () => "{}",
SET_SETTINGS: async () => "Success: Ignored in Google AI Search Mode",
SET_URL_CONTEXT: async () => "Success: Ignored in Google AI Search Mode",
SET_RESOLUTION: async () => "Success: Ignored in Google AI Search Mode",
DELETE_TURN: async () => "Success: Ignored in Google AI Search Mode",
CREATE_SHARD: async () => "Error: Context Sharding is not implemented for AI Search Mode",
INJECT_SHARD: async () => "Error: Context Sharding is not implemented for AI Search Mode",
UPLOAD_MEDIA: async () => "Error: Media Upload is not currently supported in AI Search Mode",
INJECT_DOC: async () => "Error: Doc Injection is not currently supported in AI Search Mode",
SCRAPE_HISTORY: async () => "[]"
};
const chatgptActions = {
SHUTDOWN: async () => {
clearInterval(pollIntervalId);
clearInterval(stateIntervalId);
console.log("[Harness] Shutdown command received. Loops stopped.");
return "Harness shut down.";
},
GENERATE: async (payload) => {
const input = document.querySelector('#prompt-textarea');
if (!input) return "Error: Prompt textarea not found on ChatGPT.";
const preSubmitResponses = document.querySelectorAll('[data-message-author-role="assistant"]');
const preSubmitCount = preSubmitResponses.length;
activeTactics.setNativeValue(input, payload);
await new Promise(r => setTimeout(r, 500));
const sendBtn = document.querySelector('[data-testid="send-button"]');
if (sendBtn && !sendBtn.disabled) {
sendBtn.click();
} else {
console.log("[Harness] Submit button not found or disabled, dispatching Enter key fallback...");
const enterEvent = new KeyboardEvent('keydown', { bubbles: true, cancelable: true, key: 'Enter', code: 'Enter', keyCode: 13 });
input.dispatchEvent(enterEvent);
}
console.log("[Harness] Command sent. Entering Kinetic Wait (2000ms)...");
await new Promise(r => setTimeout(r, 2000));
console.log("[Harness] Wait complete. Engaging Semantic Lock...");
return new Promise((resolve) => {
let lastTextLength = -1;
let stabilityStreak = 0;
const REQUIRED_STREAK = 2;
let maxWait = 300;
const checkLoop = setInterval(() => {
maxWait--;
if (maxWait <= 0) {
clearInterval(checkLoop);
resolve("Error: Generation timed out or hung.");
return;
}
const responses = document.querySelectorAll('[data-message-author-role="assistant"]');
if (responses.length <= preSubmitCount && responses.length !== 0) {
console.log("[Harness] Waiting for new ChatGPT response container...");
return;
}
const lastResponse = responses[responses.length - 1];
if (!lastResponse) return;
const markdownContainer = lastResponse.querySelector('.markdown') || lastResponse;
const currentTextContent = markdownContainer.innerText || "";
const currentTextLength = currentTextContent.length;
const isTextGrowing = currentTextLength > lastTextLength;
if (isTextGrowing) {
console.log(`[Harness] Status: Streaming... (+${currentTextLength - lastTextLength})`);
lastTextLength = currentTextLength;
stabilityStreak = 0;
} else if (currentTextLength === 0) {
console.log(`[Harness] Status: Waiting for text generation to begin...`);
stabilityStreak = 0;
} else {
stabilityStreak++;
console.log(`[Harness] Status: Stable... (${stabilityStreak}/${REQUIRED_STREAK})`);
lastTextLength = currentTextLength;
}
if (stabilityStreak >= REQUIRED_STREAK) {
clearInterval(checkLoop);
console.log("[Harness] Lock Released. Extraction initiated.");
let turnMd = chatgptHtmlToMarkdown(markdownContainer);
turnMd = turnMd.replace(/\n{3,}/g, '\n\n').trim();
resolve(turnMd);
}
}, 1000);
});
},
NEW_CHAT: async () => {
const newChatBtn = document.querySelector('[data-testid="create-new-chat-button"]');
if (newChatBtn) {
newChatBtn.click();
return "Chat reset.";
}
return "Error: New chat button not found.";
},
GET_CHAT_HISTORY: async () => {
const history = [];
const messages = document.querySelectorAll('[data-message-author-role]');
messages.forEach(msg => {
const role = msg.getAttribute('data-message-author-role');
if (role === 'assistant') {
const markdownContainer = msg.querySelector('.markdown') || msg;
let text = chatgptHtmlToMarkdown(markdownContainer).trim();
if (text) history.push({ role: "Model", text: text });
} else if (role === 'user') {
let text = msg.innerText.trim();
if (text) history.push({ role: "User", text: text });
}
});
return JSON.stringify(history);
},
ANALYZE_SESSION: async () => {
return JSON.stringify({
isHydrated: document.querySelectorAll('[data-message-author-role="assistant"]').length > 0,
turnCount: document.querySelectorAll('[data-message-author-role="assistant"]').length,
url: window.location.href
});
},
GET_SETTINGS: async () => "{}",
SET_SETTINGS: async () => "Success: Ignored in ChatGPT Mode",
SET_URL_CONTEXT: async () => "Success: Ignored in ChatGPT Mode",
SET_RESOLUTION: async () => "Success: Ignored in ChatGPT Mode",
DELETE_TURN: async () => "Success: Ignored in ChatGPT Mode",
CREATE_SHARD: async () => "Error: Context Sharding is not implemented for ChatGPT Mode",
INJECT_SHARD: async () => "Error: Context Sharding is not implemented for ChatGPT Mode",
UPLOAD_MEDIA: async () => "Error: Media Upload is not currently supported in ChatGPT Mode",
INJECT_DOC: async () => "Error: Doc Injection is not currently supported in ChatGPT Mode",
SCRAPE_HISTORY: async () => "[]"
};
const deepseekActions = {
SHUTDOWN: async () => {
clearInterval(pollIntervalId);
clearInterval(stateIntervalId);
console.log("[Harness] Shutdown command received. Loops stopped.");
return "Harness shut down.";
},
GENERATE: async (payload) => {
let input = document.querySelector('textarea[placeholder="Message DeepSeek"]');
if (!input) input = document.querySelector('textarea');
if (!input) return "Error: Prompt textarea not found on DeepSeek.";
const preSubmitResponses = document.querySelectorAll('.ds-assistant-message-main-content');
const preSubmitCount = preSubmitResponses.length;
activeTactics.setNativeValue(input, payload);
await new Promise(r => setTimeout(r, 800));
const sendBtn = document.querySelector('div[role="button"].ds-button--primary');
if (sendBtn && !sendBtn.classList.contains('ds-button--disabled')) {
sendBtn.click();
} else {
console.log("[Harness] Submit button not found or disabled, dispatching Enter key fallback...");
const enterEvent = new KeyboardEvent('keydown', { bubbles: true, cancelable: true, key: 'Enter', code: 'Enter', keyCode: 13 });
input.dispatchEvent(enterEvent);
}
console.log("[Harness] Command sent. Entering Kinetic Wait (2500ms)...");
await new Promise(r => setTimeout(r, 2500));
console.log("[Harness] Wait complete. Engaging Semantic Lock...");
return new Promise((resolve) => {
let lastTextLength = -1;
let stabilityStreak = 0;
const REQUIRED_STREAK = 3;
let maxWait = 600;
const checkLoop = setInterval(() => {
maxWait--;
if (maxWait <= 0) {
clearInterval(checkLoop);
resolve("Error: Generation timed out or hung.");
return;
}
const responses = document.querySelectorAll('.ds-assistant-message-main-content');
if (responses.length <= preSubmitCount && responses.length !== 0) {
console.log("[Harness] Waiting for new DeepSeek response container...");
return;
}
const lastResponse = responses[responses.length - 1];
if (!lastResponse) return;
const currentTextContent = lastResponse.innerText || "";
const currentTextLength = currentTextContent.length;
const isTextGrowing = currentTextLength > lastTextLength;
if (isTextGrowing) {
console.log(`[Harness] Status: Streaming... (+${currentTextLength - lastTextLength})`);
lastTextLength = currentTextLength;
stabilityStreak = 0;
} else if (currentTextLength === 0) {
console.log(`[Harness] Status: Thinking / Waiting for text generation to begin...`);
stabilityStreak = 0;
} else {
stabilityStreak++;
console.log(`[Harness] Status: Stable... (${stabilityStreak}/${REQUIRED_STREAK})`);
lastTextLength = currentTextLength;
}
if (stabilityStreak >= REQUIRED_STREAK) {
clearInterval(checkLoop);
console.log("[Harness] Lock Released. Extraction initiated.");
let turnMd = deepseekHtmlToMarkdown(lastResponse);
turnMd = turnMd.replace(/\n{3,}/g, '\n\n').trim();
resolve(turnMd);
}
}, 1000);
});
},
NEW_CHAT: async () => {
const spans = Array.from(document.querySelectorAll('span'));
const newChatSpan = spans.find(el => el.innerText.trim() === 'New chat');
if (newChatSpan && newChatSpan.parentElement) {
newChatSpan.parentElement.click();
return "Chat reset.";
}
return "Error: New chat button not found.";
},
GET_CHAT_HISTORY: async () => {
const history = [];
const messages = document.querySelectorAll('.ds-message');
messages.forEach(msg => {
const assistantContent = msg.querySelector('.ds-assistant-message-main-content');
if (assistantContent) {
let text = deepseekHtmlToMarkdown(assistantContent).trim();
if (text) history.push({ role: "Model", text: text });
} else {
let text = msg.innerText.trim();
if (text) history.push({ role: "User", text: text });
}
});
return JSON.stringify(history);
},
ANALYZE_SESSION: async () => {
return JSON.stringify({
isHydrated: document.querySelectorAll('.ds-assistant-message-main-content').length > 0,
turnCount: document.querySelectorAll('.ds-assistant-message-main-content').length,
url: window.location.href
});
},
GET_SETTINGS: async () => "{}",
SET_SETTINGS: async () => "Success: Ignored in DeepSeek Mode",
SET_URL_CONTEXT: async () => "Success: Ignored in DeepSeek Mode",
SET_RESOLUTION: async () => "Success: Ignored in DeepSeek Mode",
DELETE_TURN: async () => "Success: Ignored in DeepSeek Mode",
CREATE_SHARD: async () => "Error: Context Sharding is not implemented for DeepSeek Mode",
INJECT_SHARD: async () => "Error: Context Sharding is not implemented for DeepSeek Mode",
UPLOAD_MEDIA: async () => "Error: Media Upload is not currently supported in DeepSeek Mode",
INJECT_DOC: async () => "Error: Doc Injection is not currently supported in DeepSeek Mode",
SCRAPE_HISTORY: async () => "[]"
};
const geminiActions = {
SHUTDOWN: async () => {
clearInterval(pollIntervalId);
clearInterval(stateIntervalId);
console.log("[Harness] Shutdown command received. Loops stopped.");
return "Harness shut down.";
},
GENERATE: async (payload) => {
// Helper to dismiss A/B testing dialogs that block the UI
const dismissABTest = () => {
const titles = document.querySelectorAll('span.title');
for (let title of titles) {
if (title.textContent && title.textContent.includes('Which response is more helpful?')) {
const container = title.closest('.container');
if (container) {
const closeBtn = container.querySelector('button[aria-label="Close"]');
if (closeBtn) {
console.log("[Harness] Dismissing A/B test dialog...");
closeBtn.click();
}
}
}
}
};
dismissABTest();
const input = document.querySelector('.ql-editor[contenteditable="true"]');
if (!input) return "Error: Prompt textarea not found on Gemini.";
const preSubmitResponses = document.querySelectorAll('model-response');
const preSubmitCount = preSubmitResponses.length;
activeTactics.setNativeValue(input, payload);
await new Promise(r => setTimeout(r, 800));
const sendBtn = document.querySelector('button[aria-label="Send message"]');
if (sendBtn && !sendBtn.disabled && sendBtn.getAttribute('aria-disabled') !== 'true') {
sendBtn.click();
} else {
console.log("[Harness] Submit button not found or disabled, dispatching Enter key fallback...");
const enterEvent = new KeyboardEvent('keydown', { bubbles: true, cancelable: true, key: 'Enter', code: 'Enter', keyCode: 13 });
input.dispatchEvent(enterEvent);
}
console.log("[Harness] Command sent. Entering Kinetic Wait (2000ms)...");
await new Promise(r => setTimeout(r, 2000));
console.log("[Harness] Wait complete. Engaging Semantic Lock...");
return new Promise((resolve) => {
let lastTextLength = -1;
let stabilityStreak = 0;
const REQUIRED_STREAK = 3;
let maxWait = 300;
const checkLoop = setInterval(() => {
maxWait--;
if (maxWait <= 0) {
clearInterval(checkLoop);
resolve("Error: Generation timed out or hung.");
return;
}
dismissABTest();
const responses = document.querySelectorAll('model-response');
if (responses.length <= preSubmitCount && responses.length !== 0) {
console.log("[Harness] Waiting for new Gemini response container...");
return;
}
const lastResponse = responses[responses.length - 1];
if (!lastResponse) return;
const markdownContainer = lastResponse.querySelector('.markdown') || lastResponse;
const currentTextContent = markdownContainer.innerText || "";
const currentTextLength = currentTextContent.length;
const isTextGrowing = currentTextLength > lastTextLength;
// Gemini uses aria-busy to indicate active generation
const isBusy = markdownContainer.getAttribute('aria-busy') === 'true' || lastResponse.getAttribute('aria-busy') === 'true';
if (isTextGrowing || isBusy) {
console.log(`[Harness] Status: Streaming... (+${currentTextLength - lastTextLength})`);
lastTextLength = currentTextLength;
stabilityStreak = 0;
} else if (currentTextLength === 0) {
console.log(`[Harness] Status: Waiting for text generation to begin...`);
stabilityStreak = 0;
} else {
stabilityStreak++;
console.log(`[Harness] Status: Stable... (${stabilityStreak}/${REQUIRED_STREAK})`);
lastTextLength = currentTextLength;
}
if (stabilityStreak >= REQUIRED_STREAK && !isBusy) {
clearInterval(checkLoop);
console.log("[Harness] Lock Released. Extraction initiated.");
let turnMd = googleHtmlToMarkdown(markdownContainer);
turnMd = turnMd.replace(/\n{3,}/g, '\n\n').trim();
resolve(turnMd);
}
}, 1000);
});
},
NEW_CHAT: async () => {
const newChatBtn = document.querySelector('a[aria-label="New chat"]') || document.querySelector('a[href="/app"]');
if (newChatBtn) {
newChatBtn.click();
return "Chat reset.";
}
return "Error: New chat button not found.";
},
GET_CHAT_HISTORY: async () => {
const history = [];
const turns = document.querySelectorAll('user-query, model-response');
turns.forEach(turn => {
if (turn.tagName.toLowerCase() === 'USER-QUERY') {
const textEl = turn.querySelector('.query-text');
if (textEl) {
let text = textEl.textContent.replace('You said', '').trim();
if (text) history.push({ role: "User", text: text });
}
} else if (turn.tagName.toLowerCase() === 'MODEL-RESPONSE') {
const markdownContainer = turn.querySelector('.markdown');
if (markdownContainer) {
let text = googleHtmlToMarkdown(markdownContainer).trim();
if (text) history.push({ role: "Model", text: text });
}
}
});
return JSON.stringify(history);
},
ANALYZE_SESSION: async () => {
return JSON.stringify({
isHydrated: document.querySelectorAll('model-response').length > 0,
turnCount: document.querySelectorAll('model-response').length,
url: window.location.href
});
},
GET_SETTINGS: async () => "{}",
SET_SETTINGS: async () => "Success: Ignored in Gemini Mode",
SET_URL_CONTEXT: async () => "Success: Ignored in Gemini Mode",
SET_RESOLUTION: async () => "Success: Ignored in Gemini Mode",
DELETE_TURN: async () => "Success: Ignored in Gemini Mode",
CREATE_SHARD: async () => "Error: Context Sharding is not implemented for Gemini Mode",
INJECT_SHARD: async () => "Error: Context Sharding is not implemented for Gemini Mode",
UPLOAD_MEDIA: async () => "Error: Media Upload is not currently supported in Gemini Mode",
INJECT_DOC: async () => "Error: Doc Injection is not currently supported in Gemini Mode",
SCRAPE_HISTORY: async () => "[]"
};
// --- PLATFORM ASSIGNMENT ---
if (currentPlatform === 'Google') {
PLATFORM_NAME = "Google AI Search";
ID_PREFIX = "inst_gai_";
activeActions = googleActions;
activeTactics = standardTactics;
reportStateLogic = () => document.querySelectorAll('.n6owBd').length;
} else if (currentPlatform === 'ChatGPT') {
PLATFORM_NAME = "ChatGPT";
ID_PREFIX = "inst_cgpt_";
activeActions = chatgptActions;
activeTactics = contentEditableTactics;
reportStateLogic = () => document.querySelectorAll('[data-message-author-role="assistant"]').length;
} else if (currentPlatform === 'DeepSeek') {
PLATFORM_NAME = "DeepSeek";
ID_PREFIX = "inst_ds_";
activeActions = deepseekActions;
activeTactics = standardTactics;
reportStateLogic = () => document.querySelectorAll('.ds-assistant-message-main-content').length;
} else if (currentPlatform === 'Gemini') {
PLATFORM_NAME = "Google Gemini";
ID_PREFIX = "inst_gem_";
activeActions = geminiActions;
activeTactics = contentEditableTactics;
reportStateLogic = () => document.querySelectorAll('model-response').length;
}
// --- INSTANCE IDENTITY ---
function getInstanceId() {
let id = sessionStorage.getItem('tm_instance_id');
if (!id || !id.startsWith(ID_PREFIX)) {
id = ID_PREFIX + Math.random().toString(36).substr(2, 9) + '_' + Date.now();
sessionStorage.setItem('tm_instance_id', id);
}
return id;
}
const INSTANCE_ID = getInstanceId();
console.log(`[Harness] Bound to Instance ID: ${INSTANCE_ID}`);
// --- MAIN LOOP & NETWORKING ---
async function processCommand(cmdData) {
const { type, payload } = cmdData.command;
console.log(`[Harness] Processing: ${type}`, payload);
let result = "";
try {
if (activeActions[type]) {
result = await activeActions[type](payload);
} else {
result = "Unknown command type";
}
} catch (e) {
console.error("Execution failed:", e);
result = `Error: ${e.message}`;
}
console.log(`[Harness] Result for ${type}:`, result);
await sendResult(result);
}
async function sendResult(data) {
try {
await tmFetch(`${API_BASE}/result/${INSTANCE_ID}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ timestamp: Date.now(), output: data })
});
} catch (e) {
console.error("Relay failed:", e);
}
}
async function poll() {
if (isBusy || isPolling) return;
isPolling = true;
try {
const res = await tmFetch(`${API_BASE}/command/${INSTANCE_ID}`);
if (res.status === 200) {
const data = await res.json();
if (data && data.command) {
isBusy = true;
await processCommand(data);
isBusy = false;
}
}
} catch (e) {
// Network error or timeout, safely ignored.
} finally {
isPolling = false;
}
}
function reportState() {
if (isBusy) return;
const turnCount = reportStateLogic();
tmFetch(`${API_BASE}/state/${INSTANCE_ID}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
url: window.location.href,
turn_count: turnCount,
is_busy: isBusy,
platform: PLATFORM_NAME
})
}).catch(() => {});
}
pollIntervalId = setInterval(poll, POLLING_INTERVAL);
stateIntervalId = setInterval(reportState, STATE_INTERVAL);
console.log(`[Harness] ${PLATFORM_NAME} Active & Polling on Instance ${INSTANCE_ID}.`);
})();

View File

@ -27,7 +27,7 @@ The Voice Assistant PoC requires an offline voice model to function.
### 2. Install the Tampermonkey Harness ### 2. Install the Tampermonkey Harness
1. Open your browser and click the Tampermonkey extension icon -> **Create a new script**. 1. Open your browser and click the Tampermonkey extension icon -> **Create a new script**.
2. Copy the entire contents of `GoogleAI_Search_Deepseek_ChatGPT_UnifiedHarness.js` from this repository. 2. Copy the entire contents of `GoogleAI_Search_Google_Gemini_Deepseek_ChatGPT_UnifiedHarness.js` from this repository.
3. Paste it into the Tampermonkey editor, overwriting the default template. 3. Paste it into the Tampermonkey editor, overwriting the default template.
4. Go to File -> **Save** (or press Ctrl+S). 4. Go to File -> **Save** (or press Ctrl+S).