with one click
dvm
// Patch an already-downloaded HTML file to embed the divee widget (no download step). Input is a local HTML file and a site URL (root or any internal page).
// Patch an already-downloaded HTML file to embed the divee widget (no download step). Input is a local HTML file and a site URL (root or any internal page).
| name | dvm |
| description | Patch an already-downloaded HTML file to embed the divee widget (no download step). Input is a local HTML file and a site URL (root or any internal page). |
This skill patches an already-saved HTML file (SingleFile format) to embed the divee widget. Unlike divee_mockup, it does NOT download the page — the user provides the file directly. It:
analyze_site toolupdate_project_selectors tool/Users/moshe/Documents/Development/divee.ai/web/public/b92.html).https://www.b92.net) or any internal page (https://www.b92.net/info/svet/218427/.../vest). Only the scheme + host are used.Always use account ID 67841cbe-e546-4a58-a0ca-e821e11b3fac — do not ask the user for it.
Given any URL the user provides, extract just the scheme + host as the site URL:
inputUrl = "https://www.b92.net/info/svet/218427/tramp-smatra-da-je-izvrsena-smena-rezima-u-iranu/vest"
siteUrl = scheme + "://" + host → "https://www.b92.net"
If the user already provided just the root (e.g. https://www.b92.net), use it as-is. Drop any path, query, and fragment. Use siteUrl wherever SITE_URL is referenced below.
The HTML file path comes directly from the user — do NOT derive it. Use it wherever FILE_PATH is referenced below.
SingleFile captures the CMP (Consent Management Platform) loader script embedded in the page, which causes a cookie consent popup to appear. Remove it with a regex replacement:
python3 -c "
import re, sys
file = 'FILE_PATH'
with open(file, 'r', encoding='utf-8') as f:
html = f.read()
html2 = re.sub(r'<script[^>]*>\s*window\.gdprAppliesGlobally\s*=.*?</script>', '', html, flags=re.DOTALL)
if html2 == html:
print('WARN: CMP loader script not found (site may use a different CMP)')
else:
with open(file, 'w', encoding='utf-8') as f:
f.write(html2)
print('OK: cookie consent loader removed')
"
If the site uses a different CMP (OneTrust, CookieBot, etc.), adapt the regex to match that vendor's loader pattern.
Saved pages often contain empty ad slot containers (Google Publisher Tags, DFP, AdSense) that leave blank gaps in the mockup. Run replacements in a loop until no more empty containers are removed:
python3 -c "
import re
file = 'FILE_PATH'
with open(file, 'r', encoding='utf-8') as f:
html = f.read()
ad_pattern = r'<(?:div|ins|section)[^>]+(?:id|class)=\"[^\"]*(?:gpt-ad|div-gpt|dfp|adslot|ad-slot|ad-unit|ad-container|ad-wrapper|ad-placeholder|advertisement|adsbygoogle|DFPAdSlot|js-ad)[^\"]*\"[^>]*>\s*</(?:div|ins|section)>'
count = 0
while count < 10:
prev = html
html = re.sub(ad_pattern, '', html, flags=re.IGNORECASE)
count += 1
if html == prev:
break
with open(file, 'w', encoding='utf-8') as f:
f.write(html)
print(f'OK: empty ad sections cleaned (iterations: {count})')
"
The loop is needed because removing inner ad containers can expose outer wrapper containers that are now also empty.
After cleanup, read the HTML file and reason about its structure to suggest two selectors to present to the user.
Use the following snippet to extract opening tags of candidate elements, then reason over the output:
python3 -c "
import re
file = 'FILE_PATH'
with open(file, 'r', encoding='utf-8') as f:
html = f.read()
candidates = re.findall(r'<(article|main|section|div|aside)[^>]+(id|class)=\"([^\"]+)\"[^>]*>', html, re.IGNORECASE)
seen = set()
for tag, attr, val in candidates[:60]:
key = f'<{tag} {attr}=\"{val}\">'
if key not in seen:
seen.add(key)
print(key[:120])
"
From the candidate list, apply the following reasoning:
Selector 1 — Article content Look for an element that wraps the main readable body of the article. Prefer in order:
<article> elementid or class containing words like article-body, article-content, article-text, story-body, post-content, entry-content, main-content<main> element<section> or <div> that contains multiple <p> tagsOutput as the most specific CSS selector possible, e.g. div.article-body or #article-content.
Selector 2 — Widget container (inline, high in the article)
The widget should be placed inline within the article body, high up — not in a sidebar, not at the bottom, not adjacent to the article. The goal is to position it near the top of the readable content (ideally between the first and second paragraphs, or right after the featured image/lead) so it appears above the fold.
Do NOT suggest:
<aside>, sidebars, rails, or any element outside the article bodyInstead, find a stable inline anchor inside the article body. Preferred approaches in order:
A specific high-up paragraph or wrapper inside the article body, e.g. the first <p> tag inside the article content, or a wrapper div that holds the lead paragraph. Express as a CSS selector that targets that specific element (e.g. div.article-body > p:first-of-type, #story-body > p:nth-of-type(1)).
Inject a placeholder <div id="divee-slot"> into the HTML at the desired position, then use #divee-slot as the container selector. This is the most reliable approach when the article body has no naturally distinct early element. Choose an injection point that is:
To inject the placeholder, run a python replacement that finds a stable anchor in the article and inserts <div id="divee-slot"></div> immediately before or after it. Examples:
python3 -c "
import re
file = 'FILE_PATH'
with open(file, 'r', encoding='utf-8') as f:
html = f.read()
# Insert divee-slot before the FIRST <p> tag inside the article body
# Adjust the anchor regex to match the specific site's structure
anchor = re.search(r'(<article[^>]*>.*?)(<p[\s>])', html, flags=re.DOTALL)
if not anchor:
print('ERROR: anchor not found')
else:
placeholder = '<div id=\"divee-slot\"></div>'
html2 = html[:anchor.start(2)] + placeholder + html[anchor.start(2):]
with open(file, 'w', encoding='utf-8') as f:
f.write(html2)
print('OK: divee-slot placeholder injected before first <p> in article')
"
Tailor the anchor regex to the site. The above example targets the first <p> inside <article>; for sites where the article content lives in a different wrapper, anchor against that wrapper's opening tag instead.
Output as a CSS selector, e.g. #divee-slot (when using a placeholder) or div.article-body > p:first-of-type (when targeting an existing element).
Present both selectors clearly and let the user override either one before they are applied:
Article content selector : SELECTOR_1
Widget container selector: SELECTOR_2
Ask the user to confirm or supply replacements. Use the confirmed values (ARTICLE_SELECTOR, CONTAINER_SELECTOR) in Step 4b.
Call the mcp_divee_analyze_site tool with the site URL and the fixed account ID:
mcp_divee_analyze_site(url="SITE_URL", account_id="67841cbe-e546-4a58-a0ca-e821e11b3fac")
From the response, extract project_id. This is the value to use as data-project-id in the SDK script and as the project to update in Step 4b.
Apply the confirmed selectors from Step 3 to the just-created project by calling mcp_divee_update_project_selectors:
mcp_divee_update_project_selectors(
project_id="PROJECT_ID",
article_selector="ARTICLE_SELECTOR",
container_selector="CONTAINER_SELECTOR",
)
The tool maps these to project.article_class and project.widget_container_class via the widget-admin PATCH endpoint. If the user only confirmed one of the two, omit the other argument — at least one is required.
The saved HTML files (from SingleFile) contain a CSP meta tag with this default pattern:
default-src 'none'; font-src 'self' data:; img-src 'self' data:; style-src 'unsafe-inline'; media-src 'self' data:; script-src 'unsafe-inline' data:; object-src 'self' data:; frame-src 'self' data:;
Run the following command:
python3 -c "
file = 'FILE_PATH'
with open(file, 'r', encoding='utf-8') as f:
html = f.read()
old = \"default-src 'none'; font-src 'self' data:; img-src 'self' data:; style-src 'unsafe-inline'; media-src 'self' data:; script-src 'unsafe-inline' data:; object-src 'self' data:; frame-src 'self' data:;\"
new = \"default-src 'none'; font-src 'self' data:; img-src * data: blob:; style-src 'unsafe-inline'; media-src 'self' data:; script-src 'unsafe-inline' data: https://srv.divee.ai https://cdn.divee.ai; object-src 'self' data:; frame-src 'self' data:; connect-src https://srv.divee.ai https://cdn.divee.ai;\"
html2 = html.replace(old, new)
if html2 == html:
print('ERROR: no replacement - CSP pattern not found')
else:
with open(file, 'w', encoding='utf-8') as f:
f.write(html2)
print('OK: CSP updated')
"
Run this command to append the script tag, using the project_id from Step 4:
echo '' >> FILE_PATH
echo '<script src="https://srv.divee.ai/storage/v1/object/public/sdk/divee.sdk.latest.js" data-project-id="PROJECT_ID"></script>' >> FILE_PATH
echo "OK: script appended"
Replace PROJECT_ID with the project_id value returned in Step 4.
If the file lives under web/public/, the preview URL is:
https://divee.ai/<filename>
Note: Step 3 (selector suggestion) requires reasoning over the HTML and is done separately — run it after the cleanup commands below.
python3 << 'PYEOF'
import re
file = "FILE_PATH"
with open(file, "r", encoding="utf-8") as f:
html = f.read()
# Step 1 — Remove cookie consent loader
html = re.sub(r'<script[^>]*>\s*window\.gdprAppliesGlobally\s*=.*?</script>', '', html, flags=re.DOTALL)
print("OK: cookie consent loader removed")
# Step 2 — Clean up empty ad sections
ad_pattern = r'<(?:div|ins|section)[^>]+(?:id|class)="[^"]*(?:gpt-ad|div-gpt|dfp|adslot|ad-slot|ad-unit|ad-container|ad-wrapper|ad-placeholder|advertisement|adsbygoogle|DFPAdSlot|js-ad)[^"]*"[^>]*>\s*</(?:div|ins|section)>'
count = 0
while count < 10:
prev = html
html = re.sub(ad_pattern, '', html, flags=re.IGNORECASE)
count += 1
if html == prev:
break
print(f"OK: empty ad sections cleaned (iterations: {count})")
# Step 5 — Patch CSP
old = "default-src 'none'; font-src 'self' data:; img-src 'self' data:; style-src 'unsafe-inline'; media-src 'self' data:; script-src 'unsafe-inline' data:; object-src 'self' data:; frame-src 'self' data:;"
new = "default-src 'none'; font-src 'self' data:; img-src * data: blob:; style-src 'unsafe-inline'; media-src 'self' data:; script-src 'unsafe-inline' data: https://srv.divee.ai https://cdn.divee.ai; object-src 'self' data:; frame-src 'self' data:; connect-src https://srv.divee.ai https://cdn.divee.ai;"
html2 = html.replace(old, new)
if html2 == html:
print("ERROR: no replacement - CSP pattern not found")
else:
with open(file, "w", encoding="utf-8") as f:
f.write(html2)
print("OK: CSP updated")
# Step 6 — Append SDK script
with open(file, "a", encoding="utf-8") as f:
f.write('\n<script src="https://srv.divee.ai/storage/v1/object/public/sdk/divee.sdk.latest.js" data-project-id="PROJECT_ID"></script>')
print("OK: script appended")
PYEOF
[HINT] Download the complete skill directory including SKILL.md and all related files