Files
Elisabeth Rulke 95c744e7de [vercel-sandbox] rewrite skill as a comprehensive general Sandbox guide (#180)
* [vercel-sandbox] rewrite skill as a comprehensive general Sandbox guide

The published skill was a stale browser-automation recipe: it installed
packages with dnf on Amazon Linux (the default image is Ubuntu/apt) and
omitted persistence, regions, images, drives, network policy, credential
brokering, multi-agent, the CLI, and limits. Agents loading it were steered
wrong on the basics.

Rewrite skills/vercel-sandbox/upstream/SKILL.md into a full general Sandbox
skill covering the create/run/stop loop, auth, all create options, commands
(no shell, exit-code semantics), files, apt packages, ports and preview URLs,
persistence/sessions/hooks, snapshots, images, drives, network policy and
credential brokering, running AI agents via the AI Gateway, multi-agent
isolation, the CLI, limits, and a best-practice checklist. Add a summary
field to overlay.yaml as the injection-budget fallback.

Every claim is mapped to a vercel.com/docs/sandbox source or a live probe;
key runtime behaviors (non-zero exit does not throw, timeout rejects in
flight, default user is ubuntu) are BEHAVIOR_CONFIRMED against @vercel/sandbox
3.1.0. Regenerated skill build output and manifest.

* [vercel-sandbox] bump plugin version to 0.49.2

Skill content ships to users via a version bump (per #171). Bump the source
version in package.json and .claude-plugin/plugin.json, sync the per-harness
manifests (.cursor-plugin, .kimi-plugin, .plugin) and the telemetry hook
fallback, and regenerate build outputs. Addresses review feedback.
2026-09-13 13:44:56 -07:00

333 lines
9.7 KiB
JavaScript

// hooks/src/telemetry.mts
import { randomUUID } from "crypto";
import { mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from "fs";
import { join, dirname } from "path";
import { homedir } from "os";
var BRIDGE_ENDPOINT = "https://telemetry.vercel.com/api/vercel-plugin/v1/events";
var FLUSH_TIMEOUT_MS = 3e3;
var PLUGIN_VERSION = true ? "0.49.2" : "0.49.2";
var ACTIVE_SESSION_TTL_MS = 60 * 60 * 1e3;
var DAU_TOPIC_ID = "dau";
var SKILL_TOPIC_ID = "generic";
var SKILL_INVOKED_EVENT_KEY = "skill:invoked";
var SKILL_INJECTED_EVENT_KEY = "skill:injected";
var SKILL_SLUG_RE = /^[a-z0-9][a-z0-9-]{0,63}$/;
var PLUGIN_SKILL_NAMESPACES = /* @__PURE__ */ new Set(["vercel", "vercel-plugin"]);
var DAU_STAMP_PATH = join(homedir(), ".config", "vercel-plugin", "dau-stamp");
var FIRST_USE_STAMP_PATH = join(homedir(), ".config", "vercel-plugin", "first-use-stamp");
var INSTALLATION_ID_PATH = join(homedir(), ".config", "vercel-plugin", "installation-id");
var ACTIVE_SESSION_MARKER_PATH = join(homedir(), ".config", "vercel-plugin", "active-session.json");
var UUID_V4_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
var AGENT_HARNESSES = /* @__PURE__ */ new Set([
"claude-code",
"cursor",
"codex",
"github-copilot",
"kimi",
"grok",
"other",
"unknown"
]);
function isAgentHarness(value) {
return typeof value === "string" && AGENT_HARNESSES.has(value);
}
function isSkillTelemetryKey(value) {
return value === SKILL_INVOKED_EVENT_KEY || value === SKILL_INJECTED_EVENT_KEY;
}
async function sendTelemetry(events, options = { topicId: DAU_TOPIC_ID }) {
if (events.length === 0) return false;
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), FLUSH_TIMEOUT_MS);
try {
const headers = {
"Content-Type": "application/json",
"x-vercel-plugin-topic-id": options.topicId,
"x-vercel-plugin-session-id": options.sessionId ?? randomUUID(),
"x-vercel-plugin-version": PLUGIN_VERSION
};
const response = await fetch(BRIDGE_ENDPOINT, {
method: "POST",
headers,
body: JSON.stringify(events),
signal: controller.signal
});
return response.ok;
} catch {
return false;
} finally {
clearTimeout(timeout);
}
}
function getDauStampPath() {
return DAU_STAMP_PATH;
}
function getFirstUseStampPath() {
return FIRST_USE_STAMP_PATH;
}
function getInstallationIdPath() {
return INSTALLATION_ID_PATH;
}
function getAgentHarnessStampPath(agentHarness) {
return join(homedir(), ".config", "vercel-plugin", `harness-stamp-${agentHarness}`);
}
function getActiveSessionMarkerPath() {
return ACTIVE_SESSION_MARKER_PATH;
}
function readInstallationId() {
try {
const value = readFileSync(INSTALLATION_ID_PATH, "utf8").trim();
return UUID_V4_RE.test(value) ? value : null;
} catch {
return null;
}
}
function getOrCreateInstallationId() {
const existing = readInstallationId();
if (existing) return existing;
const installationId = randomUUID();
try {
mkdirSync(dirname(INSTALLATION_ID_PATH), { recursive: true, mode: 448 });
writeFileSync(INSTALLATION_ID_PATH, `${installationId}
`, {
flag: "wx",
mode: 384
});
return installationId;
} catch {
const raced = readInstallationId();
if (raced) return raced;
try {
writeFileSync(INSTALLATION_ID_PATH, `${installationId}
`, {
flag: "w",
mode: 384
});
return readInstallationId();
} catch {
return readInstallationId();
}
}
}
function utcDayStamp(date) {
return date.toISOString().slice(0, 10);
}
function shouldSendDauPing(now = /* @__PURE__ */ new Date()) {
try {
const existingMtime = statSync(DAU_STAMP_PATH).mtime;
return utcDayStamp(existingMtime) !== utcDayStamp(now);
} catch {
return true;
}
}
function shouldSendFirstUsePing() {
try {
statSync(FIRST_USE_STAMP_PATH);
return false;
} catch {
return true;
}
}
function shouldSendAgentHarnessPing(agentHarness, now = /* @__PURE__ */ new Date()) {
try {
const existingMtime = statSync(getAgentHarnessStampPath(agentHarness)).mtime;
return utcDayStamp(existingMtime) !== utcDayStamp(now);
} catch {
return true;
}
}
function markDauPingSent(now = /* @__PURE__ */ new Date()) {
void now;
try {
mkdirSync(dirname(DAU_STAMP_PATH), { recursive: true });
writeFileSync(DAU_STAMP_PATH, "", { flag: "w" });
} catch {
}
}
function markFirstUsePingSent() {
try {
mkdirSync(dirname(FIRST_USE_STAMP_PATH), { recursive: true });
writeFileSync(FIRST_USE_STAMP_PATH, "", { flag: "w" });
} catch {
}
}
function markAgentHarnessPingSent(agentHarness) {
const stampPath = getAgentHarnessStampPath(agentHarness);
try {
mkdirSync(dirname(stampPath), { recursive: true });
writeFileSync(stampPath, "", { flag: "w" });
} catch {
}
}
function removeActiveSessionMarker() {
try {
rmSync(ACTIVE_SESSION_MARKER_PATH, { force: true });
} catch {
}
}
function getTelemetryOverride(env = process.env) {
const value = env.VERCEL_PLUGIN_TELEMETRY?.trim().toLowerCase();
if (value === "off") return value;
return null;
}
function isDauTelemetryEnabled(env = process.env) {
return getTelemetryOverride(env) !== "off";
}
function refreshActiveSessionMarker(now = /* @__PURE__ */ new Date()) {
if (!isDauTelemetryEnabled()) {
removeActiveSessionMarker();
return;
}
const updatedAt = now.getTime();
const marker = {
schema: 1,
active: true,
pluginVersion: PLUGIN_VERSION,
updatedAt,
expiresAt: updatedAt + ACTIVE_SESSION_TTL_MS
};
try {
mkdirSync(dirname(ACTIVE_SESSION_MARKER_PATH), { recursive: true });
writeFileSync(ACTIVE_SESSION_MARKER_PATH, `${JSON.stringify(marker)}
`, { flag: "w" });
} catch {
}
}
async function trackDauActiveToday(now = /* @__PURE__ */ new Date(), context = {}) {
if (!isDauTelemetryEnabled()) return;
const installationId = getOrCreateInstallationId();
const agentHarness = context.agentHarness ?? "unknown";
const shouldSendAgentHarness = shouldSendAgentHarnessPing(agentHarness, now);
const eventTime = now.getTime();
const events = [];
if (shouldSendDauPing(now)) {
events.push({
id: randomUUID(),
event_time: eventTime,
key: "dau:active_today",
value: "1"
});
}
if (shouldSendFirstUsePing()) {
events.push({
id: randomUUID(),
event_time: eventTime,
key: "plugin:first_use",
value: "1"
});
}
if (events.length > 0 || shouldSendAgentHarness) {
events.push({
id: randomUUID(),
event_time: eventTime,
key: "plugin:version",
value: PLUGIN_VERSION
});
if (installationId) {
events.push({
id: randomUUID(),
event_time: eventTime,
key: "plugin:install_id",
value: installationId
});
}
if (shouldSendAgentHarness) {
events.push({
id: randomUUID(),
event_time: eventTime,
key: "plugin:agent_harness",
value: agentHarness
});
}
}
const sent = await sendTelemetry(events);
if (sent) {
for (const event of events) {
if (event.key === "dau:active_today") markDauPingSent(now);
if (event.key === "plugin:first_use") markFirstUsePingSent();
if (event.key === "plugin:agent_harness") markAgentHarnessPingSent(agentHarness);
}
}
}
function normalizeSkillInvocation(rawSkill, knownSkills) {
if (typeof rawSkill !== "string") return null;
const trimmed = rawSkill.trim().replace(/^\/+/, "");
const separator = trimmed.indexOf(":");
if (separator === -1) return null;
const namespace = trimmed.slice(0, separator).toLowerCase();
if (!PLUGIN_SKILL_NAMESPACES.has(namespace)) return null;
const slug = trimmed.slice(separator + 1).toLowerCase();
if (!SKILL_SLUG_RE.test(slug)) return null;
return knownSkills.has(slug) ? slug : null;
}
function isValidTelemetrySessionId(value) {
return typeof value === "string" && UUID_V4_RE.test(value);
}
function buildSkillEvents(key, skills, context = {}, now = /* @__PURE__ */ new Date(), installationId = readInstallationId()) {
if (skills.length === 0) return [];
const eventTime = now.getTime();
const events = skills.map((skill) => ({
id: randomUUID(),
event_time: eventTime,
key,
value: skill
}));
events.push({
id: randomUUID(),
event_time: eventTime,
key: "plugin:version",
value: PLUGIN_VERSION
});
if (installationId) {
events.push({
id: randomUUID(),
event_time: eventTime,
key: "plugin:install_id",
value: installationId
});
}
if (context.agentHarness) {
events.push({
id: randomUUID(),
event_time: eventTime,
key: "plugin:agent_harness",
value: context.agentHarness
});
}
return events;
}
async function trackSkillEvents(key, skills, context = {}, now = /* @__PURE__ */ new Date()) {
if (!isDauTelemetryEnabled() || skills.length === 0) return false;
const events = buildSkillEvents(key, skills, context, now, getOrCreateInstallationId());
return sendTelemetry(events, {
topicId: SKILL_TOPIC_ID,
sessionId: isValidTelemetrySessionId(context.telemetrySessionId) ? context.telemetrySessionId : void 0
});
}
export {
PLUGIN_VERSION,
SKILL_INJECTED_EVENT_KEY,
SKILL_INVOKED_EVENT_KEY,
buildSkillEvents,
getActiveSessionMarkerPath,
getAgentHarnessStampPath,
getDauStampPath,
getFirstUseStampPath,
getInstallationIdPath,
getTelemetryOverride,
isAgentHarness,
isDauTelemetryEnabled,
isSkillTelemetryKey,
isValidTelemetrySessionId,
markAgentHarnessPingSent,
markDauPingSent,
markFirstUsePingSent,
normalizeSkillInvocation,
refreshActiveSessionMarker,
removeActiveSessionMarker,
shouldSendAgentHarnessPing,
shouldSendDauPing,
shouldSendFirstUsePing,
trackDauActiveToday,
trackSkillEvents
};