@papi-ai/server 0.7.52 → 0.7.54
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 +73 -32
- package/dist/index.js +591 -300
- package/package.json +2 -2
|
@@ -25,6 +25,7 @@ __export(git_exports, {
|
|
|
25
25
|
detectUnrecordedCommits: () => detectUnrecordedCommits,
|
|
26
26
|
ensureLatestDevelop: () => ensureLatestDevelop,
|
|
27
27
|
ensureTagAtHead: () => ensureTagAtHead,
|
|
28
|
+
findTaskCommitsOnBase: () => findTaskCommitsOnBase,
|
|
28
29
|
getBranchDiff: () => getBranchDiff,
|
|
29
30
|
getCommitsSinceTag: () => getCommitsSinceTag,
|
|
30
31
|
getCurrentBranch: () => getCurrentBranch,
|
|
@@ -718,11 +719,29 @@ function escapeRegexLiteral(s) {
|
|
|
718
719
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
719
720
|
}
|
|
720
721
|
function detectMergedInProgress(cwd, preferredBase, tasks) {
|
|
721
|
-
if (!isGitAvailable() || !isGitRepo(cwd)) return [];
|
|
722
722
|
const inProgress = tasks.filter((t) => t.status === "In Progress");
|
|
723
723
|
if (inProgress.length === 0) return [];
|
|
724
|
+
const landed = findTaskCommitsOnBase(cwd, preferredBase, inProgress.map((t) => t.displayId));
|
|
725
|
+
const hits = [];
|
|
726
|
+
for (const task of inProgress) {
|
|
727
|
+
const hit = landed.get(task.displayId);
|
|
728
|
+
if (!hit) continue;
|
|
729
|
+
hits.push({
|
|
730
|
+
displayId: task.displayId,
|
|
731
|
+
title: task.title,
|
|
732
|
+
commit: hit.commit,
|
|
733
|
+
subject: hit.subject,
|
|
734
|
+
pr: hit.pr
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
return hits;
|
|
738
|
+
}
|
|
739
|
+
function findTaskCommitsOnBase(cwd, preferredBase, displayIds) {
|
|
740
|
+
const out = /* @__PURE__ */ new Map();
|
|
741
|
+
if (displayIds.length === 0) return out;
|
|
742
|
+
if (!isGitAvailable() || !isGitRepo(cwd)) return out;
|
|
724
743
|
const base = resolveDefaultBranch(cwd, preferredBase);
|
|
725
|
-
if (!branchExists(cwd, base)) return
|
|
744
|
+
if (!branchExists(cwd, base)) return out;
|
|
726
745
|
let raw;
|
|
727
746
|
try {
|
|
728
747
|
raw = execFileSync(
|
|
@@ -731,28 +750,25 @@ function detectMergedInProgress(cwd, preferredBase, tasks) {
|
|
|
731
750
|
{ cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }
|
|
732
751
|
);
|
|
733
752
|
} catch {
|
|
734
|
-
return
|
|
753
|
+
return out;
|
|
735
754
|
}
|
|
736
755
|
const commits = raw.split("\n").map((line) => {
|
|
737
756
|
const idx = line.indexOf("");
|
|
738
757
|
if (idx === -1) return null;
|
|
739
758
|
return { hash: line.slice(0, idx).trim(), subject: line.slice(idx + 1).trim() };
|
|
740
759
|
}).filter((c) => c !== null && c.hash !== "");
|
|
741
|
-
const
|
|
742
|
-
|
|
743
|
-
const re = new RegExp(`(^|[^\\w-])${escapeRegexLiteral(task.displayId)}([^\\w-]|$)`);
|
|
760
|
+
for (const displayId of displayIds) {
|
|
761
|
+
const re = new RegExp(`(^|[^\\w-])${escapeRegexLiteral(displayId)}([^\\w-]|$)`);
|
|
744
762
|
const hit = commits.find((c) => re.test(c.subject));
|
|
745
763
|
if (!hit) continue;
|
|
746
764
|
const prMatch = hit.subject.match(/#(\d+)/);
|
|
747
|
-
|
|
748
|
-
displayId: task.displayId,
|
|
749
|
-
title: task.title,
|
|
765
|
+
out.set(displayId, {
|
|
750
766
|
commit: hit.hash,
|
|
751
767
|
subject: hit.subject,
|
|
752
768
|
pr: prMatch ? `#${prMatch[1]}` : null
|
|
753
769
|
});
|
|
754
770
|
}
|
|
755
|
-
return
|
|
771
|
+
return out;
|
|
756
772
|
}
|
|
757
773
|
function detectUnrecordedCommits(cwd, baseBranch) {
|
|
758
774
|
if (!isGitAvailable() || !isGitRepo(cwd)) return [];
|
|
@@ -1164,21 +1180,27 @@ var init_proxy_adapter = __esm({
|
|
|
1164
1180
|
// getToolCallCount + updatePhaseStatus are ABSENT: they now have edge handlers and
|
|
1165
1181
|
// are served through the forwarder (getToolCallCount = SUP-2026-026 handler #1).
|
|
1166
1182
|
"createOwnerAction",
|
|
1167
|
-
"findPendingDocActionsForTask",
|
|
1168
1183
|
"getContributorRole",
|
|
1169
|
-
"getDecisionScorePatterns",
|
|
1170
|
-
"getModuleEstimationStats",
|
|
1171
|
-
"correctLatestBuildReportEffort",
|
|
1172
1184
|
"recordContributorReleasePr",
|
|
1173
1185
|
"setContributorReleasePrStatus",
|
|
1174
1186
|
"listContributorReleasePrs",
|
|
1175
|
-
"resolveLearningsForDoneTasks",
|
|
1176
|
-
"markCycleLearningResolved",
|
|
1177
|
-
"updateStageExitCriteria",
|
|
1178
|
-
"updateDocAction",
|
|
1179
1187
|
"claimReview",
|
|
1180
1188
|
"getSiblingAds",
|
|
1181
1189
|
"getSiblingRepoTasks"
|
|
1190
|
+
// task-2394 (C329) — Batch A wired: findPendingDocActionsForTask,
|
|
1191
|
+
// getModuleEstimationStats and getDecisionScorePatterns now have edge case handlers
|
|
1192
|
+
// (each backed by a SECURITY DEFINER RPC, migration 20260714140000) plus
|
|
1193
|
+
// ALLOWED_METHODS entries, so they forward. The two planner-context reads returned
|
|
1194
|
+
// EMPTY for every hosted user before this — the planner ran on worse context than
|
|
1195
|
+
// the owner's on the only install path external users have (AD-72).
|
|
1196
|
+
// task-2412 (C329) — listOwnerActionsForBlockerScan + linkOwnerActionToTask wired.
|
|
1197
|
+
// First USER-scoped ([C]) methods to forward: the edge binds both to the bearer's
|
|
1198
|
+
// user_id and discards the client-supplied one, so the typed-blocker scan (task-2343)
|
|
1199
|
+
// now works for hosted users without exposing one member's owner actions to another.
|
|
1200
|
+
// task-2393 (C329) — Batch B wired: markCycleLearningResolved (the P1 — hosted
|
|
1201
|
+
// discovered_issue_resolve hard-errored), correctLatestBuildReportEffort,
|
|
1202
|
+
// updateStageExitCriteria, updateDocAction, resolveLearningsForDoneTasks all have
|
|
1203
|
+
// edge case handlers + ALLOWED_METHODS/WRITE_METHODS entries now, so they forward.
|
|
1182
1204
|
// task-2489 (C320): recordProgressStep is now wired to the edge data-proxy
|
|
1183
1205
|
// (case handler + ALLOWED_METHODS/WRITE_METHODS entries), so it forwards for
|
|
1184
1206
|
// hosted callers and persists a project-scoped cycle_progress_steps row. Removed
|
|
@@ -4535,6 +4557,7 @@ Check PAPI_PROJECT_ID in your .mcp.json config. Find your project ID in the PAPI
|
|
|
4535
4557
|
}
|
|
4536
4558
|
|
|
4537
4559
|
// src/lib/formatters.ts
|
|
4560
|
+
var PLAN_FULL_NOTES_BUDGET_BYTES = Number(process.env.PAPI_PLAN_NOTES_BUDGET) || 6e4;
|
|
4538
4561
|
function effortWeight(size) {
|
|
4539
4562
|
switch ((size || "").toUpperCase()) {
|
|
4540
4563
|
case "XS":
|
|
@@ -4554,6 +4577,29 @@ function effortWeight(size) {
|
|
|
4554
4577
|
return 3;
|
|
4555
4578
|
}
|
|
4556
4579
|
}
|
|
4580
|
+
function computeCycleEffort(cycleTaskRows, cycleReports) {
|
|
4581
|
+
if (cycleTaskRows && cycleTaskRows.length > 0) {
|
|
4582
|
+
const done = cycleTaskRows.filter((t) => t.status === "Done");
|
|
4583
|
+
const reportByTask = /* @__PURE__ */ new Map();
|
|
4584
|
+
for (const r of cycleReports) if (r.taskId) reportByTask.set(r.taskId, r);
|
|
4585
|
+
return {
|
|
4586
|
+
completed: done.length,
|
|
4587
|
+
total: cycleTaskRows.length,
|
|
4588
|
+
plannedPoints: done.reduce((s, t) => s + effortWeight(t.complexity), 0),
|
|
4589
|
+
deliveredPoints: done.reduce((s, t) => {
|
|
4590
|
+
const actual = reportByTask.get(t.id)?.actualEffort;
|
|
4591
|
+
return s + effortWeight(actual || t.complexity);
|
|
4592
|
+
}, 0)
|
|
4593
|
+
};
|
|
4594
|
+
}
|
|
4595
|
+
const completed = cycleReports.filter((r) => r.completed === "Yes").length;
|
|
4596
|
+
return {
|
|
4597
|
+
completed,
|
|
4598
|
+
total: cycleReports.length,
|
|
4599
|
+
plannedPoints: cycleReports.reduce((s, r) => s + effortWeight(r.estimatedEffort || r.actualEffort), 0),
|
|
4600
|
+
deliveredPoints: cycleReports.reduce((s, r) => s + effortWeight(r.actualEffort || r.estimatedEffort), 0)
|
|
4601
|
+
};
|
|
4602
|
+
}
|
|
4557
4603
|
function computeSnapshotsFromBuildReports(reports, tasks) {
|
|
4558
4604
|
const reportsByCycle = /* @__PURE__ */ new Map();
|
|
4559
4605
|
for (const r of reports) {
|
|
@@ -4577,24 +4623,19 @@ function computeSnapshotsFromBuildReports(reports, tasks) {
|
|
|
4577
4623
|
const withEffort = cycleReports.filter((r) => r.estimatedEffort && r.actualEffort);
|
|
4578
4624
|
const accurate = withEffort.filter((r) => r.estimatedEffort === r.actualEffort).length;
|
|
4579
4625
|
const matchRate = withEffort.length > 0 ? Math.round(accurate / withEffort.length * 100) : 0;
|
|
4580
|
-
|
|
4581
|
-
let total;
|
|
4582
|
-
let effortPoints;
|
|
4583
|
-
if (cycleTaskRows && cycleTaskRows.length > 0) {
|
|
4584
|
-
const done = cycleTaskRows.filter((t) => t.status === "Done");
|
|
4585
|
-
completed = done.length;
|
|
4586
|
-
total = cycleTaskRows.length;
|
|
4587
|
-
effortPoints = done.reduce((s, t) => s + effortWeight(t.complexity), 0);
|
|
4588
|
-
} else {
|
|
4589
|
-
completed = cycleReports.filter((r) => r.completed === "Yes").length;
|
|
4590
|
-
total = cycleReports.length;
|
|
4591
|
-
effortPoints = cycleReports.reduce((s, r) => s + effortWeight(r.actualEffort), 0);
|
|
4592
|
-
}
|
|
4626
|
+
const { completed, total, plannedPoints, deliveredPoints } = computeCycleEffort(cycleTaskRows, cycleReports);
|
|
4593
4627
|
snapshots.push({
|
|
4594
4628
|
cycle: sn,
|
|
4595
4629
|
date: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4596
4630
|
accuracy: [{ cycle: sn, reports: cycleReports.length, matchRate, mae: 0, bias: 0 }],
|
|
4597
|
-
velocity: [{
|
|
4631
|
+
velocity: [{
|
|
4632
|
+
cycle: sn,
|
|
4633
|
+
completed,
|
|
4634
|
+
partial: 0,
|
|
4635
|
+
failed: Math.max(0, total - completed),
|
|
4636
|
+
effortPoints: plannedPoints,
|
|
4637
|
+
deliveredPoints
|
|
4638
|
+
}]
|
|
4598
4639
|
});
|
|
4599
4640
|
}
|
|
4600
4641
|
snapshots.sort((a, b) => a.cycle - b.cycle);
|