@papi-ai/server 0.7.46 → 0.7.47
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 +49 -14
- package/dist/index.js +86 -32
- package/dist/prompts.js +1 -1
- package/package.json +1 -1
|
@@ -4519,31 +4519,66 @@ Check PAPI_PROJECT_ID in your .mcp.json config. Find your project ID in the PAPI
|
|
|
4519
4519
|
}
|
|
4520
4520
|
|
|
4521
4521
|
// src/lib/formatters.ts
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4522
|
+
function effortWeight(size) {
|
|
4523
|
+
switch ((size || "").toUpperCase()) {
|
|
4524
|
+
case "XS":
|
|
4525
|
+
return 1;
|
|
4526
|
+
case "S":
|
|
4527
|
+
case "SMALL":
|
|
4528
|
+
return 2;
|
|
4529
|
+
case "M":
|
|
4530
|
+
case "MEDIUM":
|
|
4531
|
+
return 3;
|
|
4532
|
+
case "L":
|
|
4533
|
+
case "LARGE":
|
|
4534
|
+
return 5;
|
|
4535
|
+
case "XL":
|
|
4536
|
+
return 8;
|
|
4537
|
+
default:
|
|
4538
|
+
return 3;
|
|
4539
|
+
}
|
|
4540
|
+
}
|
|
4541
|
+
function computeSnapshotsFromBuildReports(reports, tasks) {
|
|
4542
|
+
const reportsByCycle = /* @__PURE__ */ new Map();
|
|
4526
4543
|
for (const r of reports) {
|
|
4527
|
-
const existing =
|
|
4544
|
+
const existing = reportsByCycle.get(r.cycle) ?? [];
|
|
4528
4545
|
existing.push(r);
|
|
4529
|
-
|
|
4546
|
+
reportsByCycle.set(r.cycle, existing);
|
|
4530
4547
|
}
|
|
4548
|
+
const tasksByCycle = /* @__PURE__ */ new Map();
|
|
4549
|
+
for (const t of tasks ?? []) {
|
|
4550
|
+
if (t.cycle == null) continue;
|
|
4551
|
+
const existing = tasksByCycle.get(t.cycle) ?? [];
|
|
4552
|
+
existing.push(t);
|
|
4553
|
+
tasksByCycle.set(t.cycle, existing);
|
|
4554
|
+
}
|
|
4555
|
+
const cycleNumbers = /* @__PURE__ */ new Set([...reportsByCycle.keys(), ...tasksByCycle.keys()]);
|
|
4556
|
+
if (cycleNumbers.size === 0) return [];
|
|
4531
4557
|
const snapshots = [];
|
|
4532
|
-
for (const
|
|
4533
|
-
const
|
|
4534
|
-
const
|
|
4558
|
+
for (const sn of cycleNumbers) {
|
|
4559
|
+
const cycleReports = reportsByCycle.get(sn) ?? [];
|
|
4560
|
+
const cycleTaskRows = tasksByCycle.get(sn);
|
|
4535
4561
|
const withEffort = cycleReports.filter((r) => r.estimatedEffort && r.actualEffort);
|
|
4536
4562
|
const accurate = withEffort.filter((r) => r.estimatedEffort === r.actualEffort).length;
|
|
4537
4563
|
const matchRate = withEffort.length > 0 ? Math.round(accurate / withEffort.length * 100) : 0;
|
|
4538
|
-
let
|
|
4539
|
-
|
|
4540
|
-
|
|
4564
|
+
let completed;
|
|
4565
|
+
let total;
|
|
4566
|
+
let effortPoints;
|
|
4567
|
+
if (cycleTaskRows && cycleTaskRows.length > 0) {
|
|
4568
|
+
const done = cycleTaskRows.filter((t) => t.status === "Done");
|
|
4569
|
+
completed = done.length;
|
|
4570
|
+
total = cycleTaskRows.length;
|
|
4571
|
+
effortPoints = done.reduce((s, t) => s + effortWeight(t.complexity), 0);
|
|
4572
|
+
} else {
|
|
4573
|
+
completed = cycleReports.filter((r) => r.completed === "Yes").length;
|
|
4574
|
+
total = cycleReports.length;
|
|
4575
|
+
effortPoints = cycleReports.reduce((s, r) => s + effortWeight(r.actualEffort), 0);
|
|
4541
4576
|
}
|
|
4542
4577
|
snapshots.push({
|
|
4543
4578
|
cycle: sn,
|
|
4544
4579
|
date: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4545
|
-
accuracy: [{ cycle: sn, reports:
|
|
4546
|
-
velocity: [{ cycle: sn, completed, partial: 0, failed: total - completed, effortPoints }]
|
|
4580
|
+
accuracy: [{ cycle: sn, reports: cycleReports.length, matchRate, mae: 0, bias: 0 }],
|
|
4581
|
+
velocity: [{ cycle: sn, completed, partial: 0, failed: Math.max(0, total - completed), effortPoints }]
|
|
4547
4582
|
});
|
|
4548
4583
|
}
|
|
4549
4584
|
snapshots.sort((a, b) => a.cycle - b.cycle);
|
package/dist/index.js
CHANGED
|
@@ -8306,31 +8306,66 @@ function formatBoardForReview(tasks) {
|
|
|
8306
8306
|
Notes: ${t.notes}` : ""}`
|
|
8307
8307
|
).join("\n\n");
|
|
8308
8308
|
}
|
|
8309
|
-
|
|
8310
|
-
|
|
8311
|
-
|
|
8312
|
-
|
|
8309
|
+
function effortWeight(size2) {
|
|
8310
|
+
switch ((size2 || "").toUpperCase()) {
|
|
8311
|
+
case "XS":
|
|
8312
|
+
return 1;
|
|
8313
|
+
case "S":
|
|
8314
|
+
case "SMALL":
|
|
8315
|
+
return 2;
|
|
8316
|
+
case "M":
|
|
8317
|
+
case "MEDIUM":
|
|
8318
|
+
return 3;
|
|
8319
|
+
case "L":
|
|
8320
|
+
case "LARGE":
|
|
8321
|
+
return 5;
|
|
8322
|
+
case "XL":
|
|
8323
|
+
return 8;
|
|
8324
|
+
default:
|
|
8325
|
+
return 3;
|
|
8326
|
+
}
|
|
8327
|
+
}
|
|
8328
|
+
function computeSnapshotsFromBuildReports(reports, tasks) {
|
|
8329
|
+
const reportsByCycle = /* @__PURE__ */ new Map();
|
|
8313
8330
|
for (const r of reports) {
|
|
8314
|
-
const existing =
|
|
8331
|
+
const existing = reportsByCycle.get(r.cycle) ?? [];
|
|
8315
8332
|
existing.push(r);
|
|
8316
|
-
|
|
8333
|
+
reportsByCycle.set(r.cycle, existing);
|
|
8334
|
+
}
|
|
8335
|
+
const tasksByCycle = /* @__PURE__ */ new Map();
|
|
8336
|
+
for (const t of tasks ?? []) {
|
|
8337
|
+
if (t.cycle == null) continue;
|
|
8338
|
+
const existing = tasksByCycle.get(t.cycle) ?? [];
|
|
8339
|
+
existing.push(t);
|
|
8340
|
+
tasksByCycle.set(t.cycle, existing);
|
|
8317
8341
|
}
|
|
8342
|
+
const cycleNumbers = /* @__PURE__ */ new Set([...reportsByCycle.keys(), ...tasksByCycle.keys()]);
|
|
8343
|
+
if (cycleNumbers.size === 0) return [];
|
|
8318
8344
|
const snapshots = [];
|
|
8319
|
-
for (const
|
|
8320
|
-
const
|
|
8321
|
-
const
|
|
8345
|
+
for (const sn of cycleNumbers) {
|
|
8346
|
+
const cycleReports = reportsByCycle.get(sn) ?? [];
|
|
8347
|
+
const cycleTaskRows = tasksByCycle.get(sn);
|
|
8322
8348
|
const withEffort = cycleReports.filter((r) => r.estimatedEffort && r.actualEffort);
|
|
8323
8349
|
const accurate = withEffort.filter((r) => r.estimatedEffort === r.actualEffort).length;
|
|
8324
8350
|
const matchRate = withEffort.length > 0 ? Math.round(accurate / withEffort.length * 100) : 0;
|
|
8325
|
-
let
|
|
8326
|
-
|
|
8327
|
-
|
|
8351
|
+
let completed;
|
|
8352
|
+
let total;
|
|
8353
|
+
let effortPoints;
|
|
8354
|
+
if (cycleTaskRows && cycleTaskRows.length > 0) {
|
|
8355
|
+
const done = cycleTaskRows.filter((t) => t.status === "Done");
|
|
8356
|
+
completed = done.length;
|
|
8357
|
+
total = cycleTaskRows.length;
|
|
8358
|
+
effortPoints = done.reduce((s, t) => s + effortWeight(t.complexity), 0);
|
|
8359
|
+
} else {
|
|
8360
|
+
completed = cycleReports.filter((r) => r.completed === "Yes").length;
|
|
8361
|
+
total = cycleReports.length;
|
|
8362
|
+
effortPoints = cycleReports.reduce((s, r) => s + effortWeight(r.actualEffort), 0);
|
|
8328
8363
|
}
|
|
8329
8364
|
snapshots.push({
|
|
8330
8365
|
cycle: sn,
|
|
8331
8366
|
date: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8332
|
-
accuracy: [{ cycle: sn, reports:
|
|
8333
|
-
velocity: [{ cycle: sn, completed, partial: 0, failed: total - completed, effortPoints }]
|
|
8367
|
+
accuracy: [{ cycle: sn, reports: cycleReports.length, matchRate, mae: 0, bias: 0 }],
|
|
8368
|
+
velocity: [{ cycle: sn, completed, partial: 0, failed: Math.max(0, total - completed), effortPoints }]
|
|
8334
8369
|
});
|
|
8335
8370
|
}
|
|
8336
8371
|
snapshots.sort((a, b2) => a.cycle - b2.cycle);
|
|
@@ -9274,7 +9309,7 @@ function buildHandoffsOnlyUserMessage(inputs) {
|
|
|
9274
9309
|
}
|
|
9275
9310
|
function extractDependencyChain(displayText) {
|
|
9276
9311
|
const match = displayText.match(
|
|
9277
|
-
/^##\s+Dependency Chain[^\n]*\n([\s\S]*?)(?=\n#{2,3}\s|$(?![\s\S]))/m
|
|
9312
|
+
/^##\s+Dependency Chain[^\n]*\n([\s\S]*?)(?=\n#{2,3}\s|\n-{3,}\s*(?:\n|$)|\n\s*BUILD HANDOFF\b|\n<!--\s*PAPI_STRUCTURED_OUTPUT|$(?![\s\S]))/m
|
|
9278
9313
|
);
|
|
9279
9314
|
if (!match) return void 0;
|
|
9280
9315
|
const body = match[1].trim();
|
|
@@ -12515,6 +12550,13 @@ async function preparePlan(adapter2, config2, filters, focus, force, handoffsOnl
|
|
|
12515
12550
|
contextHashes
|
|
12516
12551
|
};
|
|
12517
12552
|
}
|
|
12553
|
+
var PLAN_STAGE_STEPS = ["health-check", "inbox-triage", "board-integrity", "maturity-gate", "recommendation", "dependency-chain"];
|
|
12554
|
+
async function streamPlanStageSteps(tracker, newCycleNumber) {
|
|
12555
|
+
tracker.setStreamScope({ cycle: newCycleNumber });
|
|
12556
|
+
for (const step of PLAN_STAGE_STEPS) {
|
|
12557
|
+
await tracker.recordStep(step);
|
|
12558
|
+
}
|
|
12559
|
+
}
|
|
12518
12560
|
async function applyPlan(adapter2, config2, rawLlmOutput, mode, cycleNumber, strategyReviewWarning, contextHashes, planRunMeta, tracker) {
|
|
12519
12561
|
const applyTimer = startTimer();
|
|
12520
12562
|
console.error(`[plan-perf] applyPlan: start (llm_response=${rawLlmOutput.length} chars)`);
|
|
@@ -12527,6 +12569,7 @@ async function applyPlan(adapter2, config2, rawLlmOutput, mode, cycleNumber, str
|
|
|
12527
12569
|
if (config2.adapterType === "pg") {
|
|
12528
12570
|
tracker?.mark("process_llm_output_pg");
|
|
12529
12571
|
const result = await processLlmOutput(adapter2, config2, rawLlmOutput, mode, cycleNumber, contextHashes, planRunMeta);
|
|
12572
|
+
if (tracker) await streamPlanStageSteps(tracker, cycleNumber + 1);
|
|
12530
12573
|
const applyMs2 = applyTimer();
|
|
12531
12574
|
console.error(`[plan-perf] applyPlan: total=${applyMs2}ms (pg, no git sync)`);
|
|
12532
12575
|
return { ...result, pullNote: "", strategyReviewWarning };
|
|
@@ -13253,10 +13296,6 @@ async function handlePlan(adapter2, config2, args) {
|
|
|
13253
13296
|
}
|
|
13254
13297
|
const skipHandoffs = args.skip_handoffs === true;
|
|
13255
13298
|
const result = await preparePlan(adapter2, config2, filters, focus, force, handoffsOnly, skipHandoffs, tracker);
|
|
13256
|
-
tracker.setStreamScope({ cycle: result.cycleNumber + 1 });
|
|
13257
|
-
for (const step of ["health-check", "inbox-triage", "board-integrity", "maturity-gate", "recommendation", "dependency-chain"]) {
|
|
13258
|
-
await tracker.recordStep(step);
|
|
13259
|
-
}
|
|
13260
13299
|
planPrepareCache.set(callerKey, {
|
|
13261
13300
|
contextHashes: result.contextHashes,
|
|
13262
13301
|
userMessage: result.userMessage,
|
|
@@ -18835,7 +18874,8 @@ To override, pass force=true (emits a telemetry warning).`
|
|
|
18835
18874
|
if (adapter2.getBuildReportsSince) {
|
|
18836
18875
|
try {
|
|
18837
18876
|
const cycleReports = (await adapter2.getBuildReportsSince(currentCycle)).filter((r) => r.cycle === currentCycle);
|
|
18838
|
-
|
|
18877
|
+
const cycleTasks = (await adapter2.queryBoard({ cycleSince: currentCycle, compact: true })).filter((t) => t.cycle === currentCycle);
|
|
18878
|
+
[snapshot] = computeSnapshotsFromBuildReports(cycleReports, cycleTasks);
|
|
18839
18879
|
} catch (err) {
|
|
18840
18880
|
console.error(
|
|
18841
18881
|
`[release] cycle-metrics snapshot compute failed for cycle ${currentCycle} (non-blocking): ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -20071,6 +20111,9 @@ async function describeTask(adapter2, taskId) {
|
|
|
20071
20111
|
}
|
|
20072
20112
|
return { task };
|
|
20073
20113
|
}
|
|
20114
|
+
function shouldBlockDirtyBranchSwitch(opts) {
|
|
20115
|
+
return opts.trackedDirtyCount > 0 && opts.currentBranch !== opts.baseBranch && opts.currentBranch !== opts.featureBranch;
|
|
20116
|
+
}
|
|
20074
20117
|
async function startBuild(adapter2, config2, taskId, options = {}, clientName) {
|
|
20075
20118
|
const task = await adapter2.getTask(taskId);
|
|
20076
20119
|
if (!task) {
|
|
@@ -20192,11 +20235,11 @@ async function startBuild(adapter2, config2, taskId, options = {}, clientName) {
|
|
|
20192
20235
|
branchLines.push(`Base branch '${config2.baseBranch}' not found \u2014 using '${baseBranch}'.`);
|
|
20193
20236
|
}
|
|
20194
20237
|
const trackedDirty = getTrackedModifiedFiles(config2.projectRoot);
|
|
20195
|
-
if (trackedDirty.length
|
|
20238
|
+
if (shouldBlockDirtyBranchSwitch({ trackedDirtyCount: trackedDirty.length, currentBranch, baseBranch, featureBranch })) {
|
|
20196
20239
|
const shown = trackedDirty.slice(0, 5).join(", ");
|
|
20197
20240
|
const more = trackedDirty.length > 5 ? ` (+${trackedDirty.length - 5} more)` : "";
|
|
20198
20241
|
throw new Error(
|
|
20199
|
-
`build_execute won't switch branches: the working tree has uncommitted changes on '${currentBranch}' (this task targets '${featureBranch}'). Another session may be working there, and switching would revert those files. Commit or stash them first,
|
|
20242
|
+
`build_execute won't switch branches: the working tree has uncommitted changes on '${currentBranch}' (this task targets '${featureBranch}'). Another session may be working there, and switching would revert those files. Commit or stash them first, run build_execute from '${baseBranch}', or check out '${featureBranch}' if this is your own in-progress work. Dirty: ${shown}${more}.`
|
|
20200
20243
|
);
|
|
20201
20244
|
}
|
|
20202
20245
|
if (hasUncommittedChanges(config2.projectRoot, AUTO_WRITTEN_PATHS)) {
|
|
@@ -20369,7 +20412,8 @@ function extractDocMeta(absolutePath, relativePath, cycleNumber) {
|
|
|
20369
20412
|
}
|
|
20370
20413
|
return { title, type, cycle, summary, tags: [] };
|
|
20371
20414
|
}
|
|
20372
|
-
function assertDeployVerification(config2, input) {
|
|
20415
|
+
function assertDeployVerification(config2, input, opts = { deployingNow: true }) {
|
|
20416
|
+
if (!opts.deployingNow) return;
|
|
20373
20417
|
if (config2.adapterType !== "pg" && config2.adapterType !== "proxy") return;
|
|
20374
20418
|
let triggerHits = [];
|
|
20375
20419
|
try {
|
|
@@ -20378,6 +20422,8 @@ function assertDeployVerification(config2, input) {
|
|
|
20378
20422
|
return;
|
|
20379
20423
|
}
|
|
20380
20424
|
if (triggerHits.length === 0) return;
|
|
20425
|
+
const mergeDeployHits = triggerHits.filter((p) => !isDeployAtReleaseSurface(p));
|
|
20426
|
+
if (mergeDeployHits.length === 0) return;
|
|
20381
20427
|
const verification = input.productionVerification;
|
|
20382
20428
|
if (!verification) {
|
|
20383
20429
|
const targetLine = config2.verifyCommand ? `
|
|
@@ -20391,25 +20437,28 @@ Run a curl against the live deploy and pass production_verification on build_exe
|
|
|
20391
20437
|
{ urls, curl_command, http_status, response_excerpt, verified_at }
|
|
20392
20438
|
`;
|
|
20393
20439
|
throw new Error(
|
|
20394
|
-
`Deploy-verification required: this branch's diff touches ${
|
|
20395
|
-
` +
|
|
20396
|
-
Trigger surface is enforced because changes here have historically shipped to prod undetected (C166, C264-C265, C271).`
|
|
20440
|
+
`Deploy-verification required: this branch's diff touches ${mergeDeployHits.length} deploy-on-merge trigger-surface file(s):
|
|
20441
|
+
` + mergeDeployHits.map((p) => ` - ${p}`).join("\n") + targetLine + `
|
|
20442
|
+
Trigger surface is enforced because changes here have historically shipped to prod undetected (C166, C264-C265, C271). Edge/data-proxy diffs (supabase/functions/**) are verified at release instead.`
|
|
20397
20443
|
);
|
|
20398
20444
|
}
|
|
20399
20445
|
if (verification.http_status < 200 || verification.http_status >= 300) {
|
|
20400
20446
|
throw new Error(
|
|
20401
20447
|
`Deploy-verification failed: production_verification reports http_status=${verification.http_status} on a trigger-surface task.
|
|
20402
|
-
Trigger files touched: ${
|
|
20448
|
+
Trigger files touched: ${mergeDeployHits.join(", ")}
|
|
20403
20449
|
Fix the deploy first, then re-run build_execute complete with a 2xx verification.`
|
|
20404
20450
|
);
|
|
20405
20451
|
}
|
|
20406
20452
|
}
|
|
20453
|
+
function isDeployAtReleaseSurface(path7) {
|
|
20454
|
+
return path7.startsWith("supabase/functions/");
|
|
20455
|
+
}
|
|
20407
20456
|
async function completeBuild(adapter2, config2, taskId, input, options = {}, clientName) {
|
|
20408
20457
|
const task = await adapter2.getTask(taskId);
|
|
20409
20458
|
if (!task) {
|
|
20410
20459
|
throw new Error(`Task "${taskId}" not found on the Cycle Board.`);
|
|
20411
20460
|
}
|
|
20412
|
-
assertDeployVerification(config2, input);
|
|
20461
|
+
assertDeployVerification(config2, input, { deployingNow: options.light === true });
|
|
20413
20462
|
const [healthResult, priorCount] = await Promise.all([
|
|
20414
20463
|
adapter2.getCycleHealth().catch(() => ({ totalCycles: 0 })),
|
|
20415
20464
|
typeof adapter2.getBuildReportCountForTask === "function" ? adapter2.getBuildReportCountForTask(taskId).catch(() => 0) : Promise.resolve(0)
|
|
@@ -22195,7 +22244,7 @@ function collectDiagnostics(config2) {
|
|
|
22195
22244
|
}
|
|
22196
22245
|
var bugTool = {
|
|
22197
22246
|
name: "bug",
|
|
22198
|
-
description:
|
|
22247
|
+
description: `Report a bug OR submit an idea. Routing: a bug about PAPI itself (a PAPI tool/MCP error, the connector, a handoff/cycle problem) auto-submits UPSTREAM to PAPI maintainers with diagnostics \u2014 you do NOT need to set report=true for these. A bug in the user's OWN project auto-files as a Backlog task on their board. IMPORTANT: report=true is ONLY for a genuine PAPI-product defect \u2014 it is NOT the catch-all for "not about my app". A bug in the user's harness/editor/OS/git/other tooling (e.g. Claude Code, Codex, VS Code, a shell command) is NOT a PAPI bug: file it on the user's own board (report=false / default) or that tool's own tracker, never upstream. Override the routing explicitly: report=true forces upstream (PAPI-product only), report=false forces the user's own board. Set \`type\` ("bug"/"idea") and optional notify-when-fixed / contact-ok consent for upstream submissions. Does not call the Anthropic API.`,
|
|
22199
22248
|
annotations: { readOnlyHint: false, destructiveHint: false },
|
|
22200
22249
|
inputSchema: {
|
|
22201
22250
|
type: "object",
|
|
@@ -22227,7 +22276,7 @@ var bugTool = {
|
|
|
22227
22276
|
},
|
|
22228
22277
|
report: {
|
|
22229
22278
|
type: "boolean",
|
|
22230
|
-
description: "Routing override. Leave UNSET to auto-route: PAPI-product bugs go upstream to maintainers, project-domain bugs go to the user's board. Set true to
|
|
22279
|
+
description: "Routing override. Leave UNSET to auto-route: PAPI-product bugs go upstream to maintainers, project-domain bugs go to the user's board. Set true ONLY for a genuine PAPI-product defect (PAPI tool/MCP/connector/handoff) \u2014 a bug in the user's harness/editor/OS/other tooling is NOT a PAPI bug and must go to their own board (report=false or default), not upstream. Set false to force a task on the user's own board (use false when an auto-detected PAPI bug is actually about the user's project, harness, or environment)."
|
|
22231
22280
|
},
|
|
22232
22281
|
type: {
|
|
22233
22282
|
type: "string",
|
|
@@ -22244,7 +22293,7 @@ var bugTool = {
|
|
|
22244
22293
|
},
|
|
22245
22294
|
project: {
|
|
22246
22295
|
type: "string",
|
|
22247
|
-
description: "Project id (UUID) or slug to file this bug under, overriding the session project for THIS call only. Must be a project on your account \u2014 fails closed otherwise. Use project_switch to change the session default."
|
|
22296
|
+
description: "BOARD MODE ONLY. Project id (UUID) or slug to file this bug under, overriding the session project for THIS call only. Must be a project on your account \u2014 fails closed otherwise. It CANNOT redirect an upstream (report=true) submission \u2014 those always go to PAPI maintainers. Use project_switch to change the session default."
|
|
22248
22297
|
}
|
|
22249
22298
|
},
|
|
22250
22299
|
required: ["text"]
|
|
@@ -24698,7 +24747,12 @@ async function getHealthSummary(adapter2) {
|
|
|
24698
24747
|
try {
|
|
24699
24748
|
try {
|
|
24700
24749
|
buildReports = await adapter2.getRecentBuildReports(50);
|
|
24701
|
-
|
|
24750
|
+
let metricsTasks = [];
|
|
24751
|
+
try {
|
|
24752
|
+
metricsTasks = await adapter2.queryBoard({ cycleSince: Math.max(1, cycleNumber - 6), compact: true });
|
|
24753
|
+
} catch {
|
|
24754
|
+
}
|
|
24755
|
+
snapshots = computeSnapshotsFromBuildReports(buildReports, metricsTasks);
|
|
24702
24756
|
} catch {
|
|
24703
24757
|
}
|
|
24704
24758
|
metricsSection = formatCycleMetrics(snapshots);
|
package/dist/prompts.js
CHANGED
|
@@ -661,7 +661,7 @@ function buildHandoffsOnlyUserMessage(inputs) {
|
|
|
661
661
|
}
|
|
662
662
|
function extractDependencyChain(displayText) {
|
|
663
663
|
const match = displayText.match(
|
|
664
|
-
/^##\s+Dependency Chain[^\n]*\n([\s\S]*?)(?=\n#{2,3}\s|$(?![\s\S]))/m
|
|
664
|
+
/^##\s+Dependency Chain[^\n]*\n([\s\S]*?)(?=\n#{2,3}\s|\n-{3,}\s*(?:\n|$)|\n\s*BUILD HANDOFF\b|\n<!--\s*PAPI_STRUCTURED_OUTPUT|$(?![\s\S]))/m
|
|
665
665
|
);
|
|
666
666
|
if (!match) return void 0;
|
|
667
667
|
const body = match[1].trim();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@papi-ai/server",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.47",
|
|
4
4
|
"description": "PAPI MCP server \u2014 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",
|