Add versioned telemetry events

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
dotta 2026-04-03 07:32:54 -05:00
parent 2ac40aba56
commit 37b6ad42ea
16 changed files with 577 additions and 0 deletions

View file

@ -6,10 +6,20 @@ import {
companySkillImportSchema,
companySkillProjectScanRequestSchema,
} from "@paperclipai/shared";
import { trackSkillImported } from "@paperclipai/shared/telemetry";
import { validate } from "../middleware/validate.js";
import { accessService, agentService, companySkillService, logActivity } from "../services/index.js";
import { forbidden } from "../errors.js";
import { assertCompanyAccess, getActorInfo } from "./authz.js";
import { getTelemetryClient } from "../telemetry.js";
type SkillTelemetryInput = {
key: string;
slug: string;
sourceType: string;
sourceLocator: string | null;
metadata: Record<string, unknown> | null;
};
export function companySkillRoutes(db: Db) {
const router = Router();
@ -22,6 +32,26 @@ export function companySkillRoutes(db: Db) {
return Boolean((agent.permissions as Record<string, unknown>).canCreateAgents);
}
function asString(value: unknown): string | null {
if (typeof value !== "string") return null;
const trimmed = value.trim();
return trimmed.length > 0 ? trimmed : null;
}
function deriveTrackedSkillRef(skill: SkillTelemetryInput): string | null {
if (skill.sourceType === "skills_sh") {
return skill.key;
}
if (skill.sourceType !== "github") {
return null;
}
const hostname = asString(skill.metadata?.hostname) ?? "github.com";
if (hostname !== "github.com") {
return null;
}
return skill.key;
}
async function assertCanMutateCompanySkills(req: Request, companyId: string) {
assertCompanyAccess(req, companyId);
@ -183,6 +213,15 @@ export function companySkillRoutes(db: Db) {
warningCount: result.warnings.length,
},
});
const telemetryClient = getTelemetryClient();
if (telemetryClient) {
for (const skill of result.imported) {
trackSkillImported(telemetryClient, {
sourceType: skill.sourceType,
skillRef: deriveTrackedSkillRef(skill),
});
}
}
res.status(201).json(result);
},