@papi-ai/server 0.7.54 → 0.7.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backfill-cycle-metrics.js +8 -7
- package/dist/index.js +32 -23
- package/package.json +2 -2
|
@@ -1065,7 +1065,7 @@ var init_install_id = __esm({
|
|
|
1065
1065
|
function reportTelemetryEmitFailure(reason, ctx) {
|
|
1066
1066
|
consecutiveTelemetryFailures += 1;
|
|
1067
1067
|
console.error(
|
|
1068
|
-
`[telemetry] emit failed (${reason}) tool=${ctx.toolName} event=${ctx.eventType} project=${ctx.projectId}`
|
|
1068
|
+
`[telemetry] emit failed (${reason}) tool=${ctx.toolName} event=${ctx.eventType} project=${ctx.projectId ?? "(none)"}`
|
|
1069
1069
|
);
|
|
1070
1070
|
if (consecutiveTelemetryFailures >= TELEMETRY_BLACKOUT_THRESHOLD) {
|
|
1071
1071
|
console.error(
|
|
@@ -1561,18 +1561,19 @@ Check PAPI_PROJECT_ID in your .mcp.json config. Find your project ID in the PAPI
|
|
|
1561
1561
|
*/
|
|
1562
1562
|
emitTelemetry(event) {
|
|
1563
1563
|
const ctx = { projectId: event.projectId, toolName: event.toolName, eventType: event.eventType };
|
|
1564
|
+
const payload = {
|
|
1565
|
+
toolName: event.toolName,
|
|
1566
|
+
eventType: event.eventType,
|
|
1567
|
+
metadata: event.metadata ?? {}
|
|
1568
|
+
};
|
|
1569
|
+
if (event.projectId) payload["projectId"] = event.projectId;
|
|
1564
1570
|
fetch(`${this.endpoint}/telemetry`, {
|
|
1565
1571
|
method: "POST",
|
|
1566
1572
|
headers: {
|
|
1567
1573
|
"Content-Type": "application/json",
|
|
1568
1574
|
"Authorization": `Bearer ${this.apiKey}`
|
|
1569
1575
|
},
|
|
1570
|
-
body: JSON.stringify(
|
|
1571
|
-
projectId: event.projectId,
|
|
1572
|
-
toolName: event.toolName,
|
|
1573
|
-
eventType: event.eventType,
|
|
1574
|
-
metadata: event.metadata ?? {}
|
|
1575
|
-
}),
|
|
1576
|
+
body: JSON.stringify(payload),
|
|
1576
1577
|
signal: AbortSignal.timeout(5e3)
|
|
1577
1578
|
}).then((res) => {
|
|
1578
1579
|
if (res.ok) noteTelemetryEmitSuccess();
|
package/dist/index.js
CHANGED
|
@@ -1103,7 +1103,7 @@ function isEnabled() {
|
|
|
1103
1103
|
function reportTelemetryEmitFailure(reason, ctx) {
|
|
1104
1104
|
consecutiveTelemetryFailures += 1;
|
|
1105
1105
|
console.error(
|
|
1106
|
-
`[telemetry] emit failed (${reason}) tool=${ctx.toolName} event=${ctx.eventType} project=${ctx.projectId}`
|
|
1106
|
+
`[telemetry] emit failed (${reason}) tool=${ctx.toolName} event=${ctx.eventType} project=${ctx.projectId ?? "(none)"}`
|
|
1107
1107
|
);
|
|
1108
1108
|
if (consecutiveTelemetryFailures >= TELEMETRY_BLACKOUT_THRESHOLD) {
|
|
1109
1109
|
console.error(
|
|
@@ -1120,11 +1120,11 @@ function emitTelemetryEvent(event) {
|
|
|
1120
1120
|
if (!apiKey) return;
|
|
1121
1121
|
const endpoint = process.env["PAPI_DATA_ENDPOINT"] ?? DEFAULT_TELEMETRY_ENDPOINT;
|
|
1122
1122
|
const body = {
|
|
1123
|
-
projectId: event.project_id,
|
|
1124
1123
|
toolName: event.tool_name,
|
|
1125
1124
|
eventType: event.event_type,
|
|
1126
1125
|
metadata: event.metadata ?? {}
|
|
1127
1126
|
};
|
|
1127
|
+
if (event.project_id) body["projectId"] = event.project_id;
|
|
1128
1128
|
const ctx = {
|
|
1129
1129
|
projectId: event.project_id,
|
|
1130
1130
|
toolName: event.tool_name,
|
|
@@ -1678,18 +1678,19 @@ Check PAPI_PROJECT_ID in your .mcp.json config. Find your project ID in the PAPI
|
|
|
1678
1678
|
*/
|
|
1679
1679
|
emitTelemetry(event) {
|
|
1680
1680
|
const ctx = { projectId: event.projectId, toolName: event.toolName, eventType: event.eventType };
|
|
1681
|
+
const payload = {
|
|
1682
|
+
toolName: event.toolName,
|
|
1683
|
+
eventType: event.eventType,
|
|
1684
|
+
metadata: event.metadata ?? {}
|
|
1685
|
+
};
|
|
1686
|
+
if (event.projectId) payload["projectId"] = event.projectId;
|
|
1681
1687
|
fetch(`${this.endpoint}/telemetry`, {
|
|
1682
1688
|
method: "POST",
|
|
1683
1689
|
headers: {
|
|
1684
1690
|
"Content-Type": "application/json",
|
|
1685
1691
|
"Authorization": `Bearer ${this.apiKey}`
|
|
1686
1692
|
},
|
|
1687
|
-
body: JSON.stringify(
|
|
1688
|
-
projectId: event.projectId,
|
|
1689
|
-
toolName: event.toolName,
|
|
1690
|
-
eventType: event.eventType,
|
|
1691
|
-
metadata: event.metadata ?? {}
|
|
1692
|
-
}),
|
|
1693
|
+
body: JSON.stringify(payload),
|
|
1693
1694
|
signal: AbortSignal.timeout(5e3)
|
|
1694
1695
|
}).then((res) => {
|
|
1695
1696
|
if (res.ok) noteTelemetryEmitSuccess();
|
|
@@ -8411,6 +8412,9 @@ function computeCycleEffort(cycleTaskRows, cycleReports) {
|
|
|
8411
8412
|
deliveredPoints: cycleReports.reduce((s, r) => s + effortWeight(r.actualEffort || r.estimatedEffort), 0)
|
|
8412
8413
|
};
|
|
8413
8414
|
}
|
|
8415
|
+
function velocityPoints(v) {
|
|
8416
|
+
return v.deliveredPoints ?? v.effortPoints;
|
|
8417
|
+
}
|
|
8414
8418
|
function computeSnapshotsFromBuildReports(reports, tasks) {
|
|
8415
8419
|
const reportsByCycle = /* @__PURE__ */ new Map();
|
|
8416
8420
|
for (const r of reports) {
|
|
@@ -8461,22 +8465,22 @@ function formatCycleMetrics(snapshots) {
|
|
|
8461
8465
|
const avgPlanned = Math.round(
|
|
8462
8466
|
recentVelocities.reduce((sum, v) => sum + v.effortPoints, 0) / recentVelocities.length * 10
|
|
8463
8467
|
) / 10;
|
|
8464
|
-
const
|
|
8465
|
-
|
|
8466
|
-
|
|
8468
|
+
const avgDelivered = Math.round(
|
|
8469
|
+
recentVelocities.reduce((sum, v) => sum + velocityPoints(v), 0) / recentVelocities.length * 10
|
|
8470
|
+
) / 10;
|
|
8471
|
+
const anyDelivered = recentVelocities.some((v) => v.deliveredPoints !== void 0);
|
|
8472
|
+
lines.push("**Velocity \u2014 delivered effort points (size the next cycle from this)**");
|
|
8467
8473
|
lines.push(
|
|
8468
|
-
`- Last ${recentVelocities.length} cycles: ` + recentVelocities.map((v) => v.deliveredPoints !== void 0 ? `S${v.cycle}=${v.
|
|
8474
|
+
`- Last ${recentVelocities.length} cycles: ` + recentVelocities.map((v) => v.deliveredPoints !== void 0 ? `S${v.cycle}=${v.deliveredPoints} delivered/${v.effortPoints} planned` : `S${v.cycle}=${v.effortPoints} planned (no delivered data \u2014 using planned)`).join(", ")
|
|
8469
8475
|
);
|
|
8470
|
-
|
|
8476
|
+
lines.push(`- Velocity (avg delivered): ${avgDelivered} pts/cycle (XS=1, S=2, M=3, L=5, XL=8)`);
|
|
8477
|
+
if (anyDelivered) {
|
|
8471
8478
|
const delta = Math.round((avgDelivered - avgPlanned) * 10) / 10;
|
|
8472
8479
|
const sign = delta > 0 ? "+" : "";
|
|
8473
8480
|
const read = delta === 0 ? "delivered matches planned" : delta > 0 ? "cycles cost MORE than scoped (under-scoping)" : "cycles cost LESS than scoped (over-scoping)";
|
|
8474
|
-
lines.push(`-
|
|
8475
|
-
lines.push(`- Scope accuracy: ${sign}${delta} pts/cycle \u2014 ${read}.`);
|
|
8476
|
-
} else {
|
|
8477
|
-
lines.push(`- Average: ${avgPlanned} planned effort points/cycle (XS=1, S=2, M=3, L=5, XL=8)`);
|
|
8481
|
+
lines.push(`- Scope accuracy (drift vs planned): planned averaged ${avgPlanned} pts/cycle \u2014 ${sign}${delta} pts, ${read}.`);
|
|
8478
8482
|
}
|
|
8479
|
-
lines.push(`- Size cycles on what the selected tasks actually
|
|
8483
|
+
lines.push(`- Size cycles on what the selected tasks actually cost \u2014 delivered is the signal, planned is the estimate that was wrong.`);
|
|
8480
8484
|
}
|
|
8481
8485
|
return lines.join("\n");
|
|
8482
8486
|
}
|
|
@@ -8490,7 +8494,9 @@ function formatDerivedMetrics(snapshots, backlogTasks) {
|
|
|
8490
8494
|
const latest = recent[recent.length - 1];
|
|
8491
8495
|
lines.push("**Cycle History (5-cycle avg)**");
|
|
8492
8496
|
lines.push(`- Average: ${avg.toFixed(1)} tasks/cycle`);
|
|
8493
|
-
|
|
8497
|
+
const latestDelivered = velocityPoints(latest);
|
|
8498
|
+
const plannedNote = latest.deliveredPoints !== void 0 && latest.deliveredPoints !== latest.effortPoints ? ` (planned ${latest.effortPoints})` : "";
|
|
8499
|
+
lines.push(`- Latest (Cycle ${latest.cycle}): ${latest.completed} tasks, ${latestDelivered} effort points delivered${plannedNote}`);
|
|
8494
8500
|
}
|
|
8495
8501
|
}
|
|
8496
8502
|
const activeTasks = backlogTasks.filter(
|
|
@@ -14072,6 +14078,7 @@ function extractTrendPoints(snapshots) {
|
|
|
14072
14078
|
matchRate: accuracyRow.matchRate,
|
|
14073
14079
|
bias: accuracyRow.bias,
|
|
14074
14080
|
effortPoints: velocityRow.effortPoints,
|
|
14081
|
+
deliveredPoints: velocityPoints(velocityRow),
|
|
14075
14082
|
completed: velocityRow.completed
|
|
14076
14083
|
});
|
|
14077
14084
|
}
|
|
@@ -14085,7 +14092,8 @@ function generateValueReport(snapshots) {
|
|
|
14085
14092
|
const first = recent[0];
|
|
14086
14093
|
const last = recent[recent.length - 1];
|
|
14087
14094
|
const matchRateDelta = last.matchRate - first.matchRate;
|
|
14088
|
-
const effortDelta = last.
|
|
14095
|
+
const effortDelta = last.deliveredPoints - first.deliveredPoints;
|
|
14096
|
+
const plannedDelta = last.effortPoints - first.effortPoints;
|
|
14089
14097
|
const completedDelta = last.completed - first.completed;
|
|
14090
14098
|
const biasTrend = assessBiasTrend(first.bias, last.bias);
|
|
14091
14099
|
const lines = [];
|
|
@@ -14094,7 +14102,8 @@ function generateValueReport(snapshots) {
|
|
|
14094
14102
|
lines.push("");
|
|
14095
14103
|
lines.push(`- **Scope accuracy:** ${first.matchRate}% \u2192 ${last.matchRate}% (${formatDelta(matchRateDelta, "pp")})`);
|
|
14096
14104
|
lines.push(`- **Estimation bias:** ${formatBias(first.bias)} \u2192 ${formatBias(last.bias)} (${biasTrend})`);
|
|
14097
|
-
lines.push(`- **Velocity:** ${first.
|
|
14105
|
+
lines.push(`- **Velocity (delivered):** ${first.deliveredPoints} \u2192 ${last.deliveredPoints} effort points/cycle (${formatDelta(effortDelta, "")})`);
|
|
14106
|
+
lines.push(`- **Planned (for drift):** ${first.effortPoints} \u2192 ${last.effortPoints} effort points/cycle (${formatDelta(plannedDelta, "")})`);
|
|
14098
14107
|
lines.push(`- **Throughput:** ${first.completed} \u2192 ${last.completed} tasks/cycle (${formatDelta(completedDelta, "")})`);
|
|
14099
14108
|
return lines.join("\n");
|
|
14100
14109
|
}
|
|
@@ -24992,7 +25001,7 @@ function computeHealthScore(cycleNumber, snapshots, activeTasks, decisionUsage)
|
|
|
24992
25001
|
const recentSnaps = snapshots.slice(-3);
|
|
24993
25002
|
const baselineSnaps = snapshots.slice(-10);
|
|
24994
25003
|
if (recentSnaps.length > 0 && baselineSnaps.length > 0) {
|
|
24995
|
-
const avg = (snaps) => snaps.reduce((s, sn) => s + (sn.velocity[0]
|
|
25004
|
+
const avg = (snaps) => snaps.reduce((s, sn) => s + (sn.velocity[0] ? velocityPoints(sn.velocity[0]) : 0), 0) / snaps.length;
|
|
24996
25005
|
const recentAvg = avg(recentSnaps);
|
|
24997
25006
|
const baselineAvg = avg(baselineSnaps);
|
|
24998
25007
|
const velocityScore = baselineAvg > 0 ? Math.min(100, Math.round(recentAvg / baselineAvg * 100)) : 50;
|
|
@@ -29064,7 +29073,7 @@ ${usageLine(decision.usage)}`;
|
|
|
29064
29073
|
emitMdAdapterPing(name, { duration_ms: elapsed, success: !isError }, config2.userId, mdProjectSlug);
|
|
29065
29074
|
}
|
|
29066
29075
|
const telemetryProjectId = resolveTelemetryProjectId(config2);
|
|
29067
|
-
|
|
29076
|
+
{
|
|
29068
29077
|
const adapterEmit = adapter2.emitTelemetry?.bind(adapter2) ?? null;
|
|
29069
29078
|
if (adapterEmit) {
|
|
29070
29079
|
adapterEmit({
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@papi-ai/server",
|
|
3
|
-
"version": "0.7.
|
|
4
|
-
"description": "PAPI MCP server
|
|
3
|
+
"version": "0.7.55",
|
|
4
|
+
"description": "PAPI MCP server — AI-powered sprint planning, build execution, and strategy review for software projects",
|
|
5
5
|
"license": "Elastic-2.0",
|
|
6
6
|
"mcpName": "io.github.getpapi/papi",
|
|
7
7
|
"type": "module",
|