UNPKG

@workflow-manager/runner

Version:

CLI runner for in-memory and markdown workflow orchestration using ATEP-like envelopes

70 lines (69 loc) 2.97 kB
import fs from "node:fs"; import path from "node:path"; import { resolveAuthToken } from "./config.js"; import { trackRunTelemetry } from "./api.js"; function workflowSourceFormat(filePath) { return path.extname(filePath).toLowerCase() === ".json" ? "json" : "markdown"; } function cliVersion() { try { const packagePath = path.resolve(process.cwd(), "package.json"); const parsed = JSON.parse(fs.readFileSync(packagePath, "utf-8")); return typeof parsed.version === "string" ? parsed.version : null; } catch { return null; } } export function buildRunTelemetryPayload(options) { const { definition, sourceFilePath, durationMs, result, failureReason } = options; const stepRuns = result?.stepRuns ?? []; const succeededSteps = stepRuns.filter((step) => step.status === "succeeded").length; const failedSteps = stepRuns.filter((step) => step.status === "failed").length; const waitingSteps = stepRuns.filter((step) => step.status === "waiting_for_approval").length; const cancelledSteps = stepRuns.filter((step) => step.status === "cancelled").length; const retriedSteps = stepRuns.reduce((sum, step) => sum + Math.max(step.attempt - 1, 0), 0); const totalSteps = definition.steps.length; const successRatio = totalSteps === 0 ? 0 : succeededSteps / totalSteps; const retryPenalty = totalSteps === 0 ? 0 : Math.min(retriedSteps / totalSteps, 1) * 20; const waitingPenalty = waitingSteps > 0 ? 15 : 0; const failurePenalty = failedSteps > 0 ? 35 : 0; const effectivenessScore = Math.max(0, Math.min(100, Math.round(successRatio * 100 - retryPenalty - waitingPenalty - failurePenalty))); const terminalState = (result?.status ?? "failed"); return { workflowKey: definition.key, workflowTitle: definition.title, runId: result?.runId ?? `failed-preflight:${definition.key}`, terminalState, totalSteps, succeededSteps, failedSteps, waitingSteps, cancelledSteps, retriedSteps, eventCount: result?.events.length ?? 0, durationMs, effectivenessScore, outputKeys: Object.keys(result?.outputs ?? {}), sourceName: path.basename(sourceFilePath), sourceFormat: workflowSourceFormat(sourceFilePath), cliVersion: cliVersion(), failureReason: failureReason ?? (terminalState === "failed" ? "run failed" : null), metadata: { workflowObjectives: definition.objectives ?? [], stepKeys: definition.steps.map((step) => step.key), outputCount: Object.keys(result?.outputs ?? {}).length, }, }; } export async function emitRunTelemetryBestEffort(options) { if (!resolveAuthToken()) { return; } try { await trackRunTelemetry(buildRunTelemetryPayload(options)); } catch (error) { console.warn(`Telemetry warning: ${error.message}`); } }