- Add full Telegram bot functionality with Z.AI API integration
- Implement 4 tools: Bash, FileEdit, WebSearch, Git
- Add 3 agents: Code Reviewer, Architect, DevOps Engineer
- Add 6 skills for common coding tasks
- Add systemd service file for 24/7 operation
- Add nginx configuration for HTTPS webhook
- Add comprehensive documentation
- Implement WebSocket server for real-time updates
- Add logging system with Winston
- Add environment validation
🤖 zCode CLI X - Agentic coder with Z.AI + Telegram integration
191 lines
5.7 KiB
JavaScript
191 lines
5.7 KiB
JavaScript
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.autoAttributesPlugin = autoAttributesPlugin;
|
|
function getBrowserDevice(ua) {
|
|
const browser = ua.match(/Edg/) ? "edge" : ua.match(/Chrome/) ? "chrome" : ua.match(/Firefox/) ? "firefox" : ua.match(/Safari/) ? "safari" : "unknown";
|
|
const deviceType = ua.match(/Mobi/) ? "mobile" : "desktop";
|
|
return {
|
|
browser,
|
|
deviceType
|
|
};
|
|
}
|
|
function getURLAttributes(url) {
|
|
if (!url) return {};
|
|
return {
|
|
url: url.href,
|
|
path: url.pathname,
|
|
host: url.host,
|
|
query: url.search
|
|
};
|
|
}
|
|
function autoAttributesPlugin(settings = {}) {
|
|
// Browser only
|
|
if (typeof window === "undefined") {
|
|
throw new Error("autoAttributesPlugin only works in the browser");
|
|
}
|
|
const COOKIE_NAME = settings.uuidCookieName || "gbuuid";
|
|
const uuidKey = settings.uuidKey || "id";
|
|
let uuid = settings.uuid || "";
|
|
function persistUUID() {
|
|
setCookie(COOKIE_NAME, uuid);
|
|
}
|
|
function getUUID() {
|
|
// Already stored in memory, return
|
|
if (uuid) return uuid;
|
|
|
|
// If cookie is already set, return
|
|
uuid = getCookie(COOKIE_NAME);
|
|
if (uuid) return uuid;
|
|
|
|
// Generate a new UUID
|
|
uuid = genUUID(window.crypto);
|
|
return uuid;
|
|
}
|
|
|
|
// Listen for a custom event to persist the UUID cookie
|
|
document.addEventListener("growthbookpersist", () => {
|
|
persistUUID();
|
|
});
|
|
function getAutoAttributes(settings) {
|
|
const ua = navigator.userAgent;
|
|
const _uuid = getUUID();
|
|
|
|
// If a uuid is provided, default persist to false, otherwise default to true
|
|
if (settings.uuidAutoPersist ?? !settings.uuid) {
|
|
persistUUID();
|
|
}
|
|
const url = location;
|
|
return {
|
|
...getDataLayerVariables(),
|
|
[uuidKey]: _uuid,
|
|
...getURLAttributes(url),
|
|
pageTitle: document.title,
|
|
...getBrowserDevice(ua),
|
|
...getUtmAttributes(url)
|
|
};
|
|
}
|
|
return gb => {
|
|
// Only works for instances with user attributes
|
|
if ("createScopedInstance" in gb) {
|
|
return;
|
|
}
|
|
|
|
// Set initial attributes
|
|
const attributes = getAutoAttributes(settings);
|
|
attributes.url && gb.setURL(attributes.url);
|
|
gb.updateAttributes(attributes);
|
|
|
|
// Poll for URL changes and update GrowthBook
|
|
let currentUrl = attributes.url;
|
|
const intervalTimer = setInterval(() => {
|
|
if (location.href !== currentUrl) {
|
|
currentUrl = location.href;
|
|
gb.setURL(currentUrl);
|
|
gb.updateAttributes(getAutoAttributes(settings));
|
|
}
|
|
}, 500);
|
|
|
|
// Listen for a custom event to update URL and attributes
|
|
const refreshListener = () => {
|
|
if (location.href !== currentUrl) {
|
|
currentUrl = location.href;
|
|
gb.setURL(currentUrl);
|
|
}
|
|
gb.updateAttributes(getAutoAttributes(settings));
|
|
};
|
|
document.addEventListener("growthbookrefresh", refreshListener);
|
|
if ("onDestroy" in gb) {
|
|
gb.onDestroy(() => {
|
|
clearInterval(intervalTimer);
|
|
document.removeEventListener("growthbookrefresh", refreshListener);
|
|
});
|
|
}
|
|
};
|
|
}
|
|
function setCookie(name, value) {
|
|
const d = new Date();
|
|
const COOKIE_DAYS = 400; // 400 days is the max cookie duration for chrome
|
|
d.setTime(d.getTime() + 24 * 60 * 60 * 1000 * COOKIE_DAYS);
|
|
document.cookie = name + "=" + value + ";path=/;expires=" + d.toUTCString();
|
|
}
|
|
function getCookie(name) {
|
|
const value = "; " + document.cookie;
|
|
const parts = value.split(`; ${name}=`);
|
|
return parts.length === 2 ? parts[1].split(";")[0] : "";
|
|
}
|
|
|
|
// Use the browsers crypto.randomUUID if set to generate a UUID
|
|
function genUUID(crypto) {
|
|
if (crypto && crypto.randomUUID) return crypto.randomUUID();
|
|
return ("" + 1e7 + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => {
|
|
const n = crypto && crypto.getRandomValues ? crypto.getRandomValues(new Uint8Array(1))[0] : Math.floor(Math.random() * 256);
|
|
return (c ^ n & 15 >> c / 4).toString(16);
|
|
});
|
|
}
|
|
function getUtmAttributes(url) {
|
|
// Store utm- params in sessionStorage for future page loads
|
|
let utms = {};
|
|
try {
|
|
const existing = sessionStorage.getItem("utm_params");
|
|
if (existing) {
|
|
utms = JSON.parse(existing);
|
|
}
|
|
} catch (e) {
|
|
// Do nothing if sessionStorage is disabled (e.g. incognito window)
|
|
}
|
|
|
|
// Add utm params from querystring
|
|
if (url && url.search) {
|
|
const params = new URLSearchParams(url.search);
|
|
let hasChanges = false;
|
|
["source", "medium", "campaign", "term", "content"].forEach(k => {
|
|
// Querystring is in snake_case
|
|
const param = `utm_${k}`;
|
|
// Attribute keys are camelCase
|
|
const attr = `utm` + k[0].toUpperCase() + k.slice(1);
|
|
if (params.has(param)) {
|
|
utms[attr] = params.get(param) || "";
|
|
hasChanges = true;
|
|
}
|
|
});
|
|
|
|
// Write back to sessionStorage
|
|
if (hasChanges) {
|
|
try {
|
|
sessionStorage.setItem("utm_params", JSON.stringify(utms));
|
|
} catch (e) {
|
|
// Do nothing if sessionStorage is disabled (e.g. incognito window)
|
|
}
|
|
}
|
|
}
|
|
return utms;
|
|
}
|
|
function getDataLayerVariables() {
|
|
if (typeof window === "undefined" || !window.dataLayer || !window.dataLayer.forEach) {
|
|
return {};
|
|
}
|
|
const obj = {};
|
|
window.dataLayer.forEach(item => {
|
|
// Skip empty and non-object entries
|
|
if (!item || typeof item !== "object" || "length" in item) return;
|
|
|
|
// Skip events
|
|
if ("event" in item) return;
|
|
Object.keys(item).forEach(k => {
|
|
// Filter out known properties that aren't useful
|
|
if (typeof k !== "string" || k.match(/^(gtm)/)) return;
|
|
const val = item[k];
|
|
|
|
// Only add primitive variable values
|
|
const valueType = typeof val;
|
|
if (["string", "number", "boolean"].includes(valueType)) {
|
|
obj[k] = val;
|
|
}
|
|
});
|
|
});
|
|
return obj;
|
|
}
|
|
//# sourceMappingURL=auto-attributes.js.map
|