@papi-ai/server 0.7.55 → 0.7.57

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.
@@ -1179,8 +1179,11 @@ var init_proxy_adapter = __esm({
1179
1179
  // (2) not-yet-wired hosted gaps — shrink as data-proxy handlers land (task-2390).
1180
1180
  // getToolCallCount + updatePhaseStatus are ABSENT: they now have edge handlers and
1181
1181
  // are served through the forwarder (getToolCallCount = SUP-2026-026 handler #1).
1182
- "createOwnerAction",
1183
1182
  "getContributorRole",
1183
+ // task-2728 (C331): createOwnerAction REMOVED from NO_FORWARD — the PRODUCER half
1184
+ // of the owner-action queue. Six readers were wired C329 (task-2412) but the
1185
+ // producer stayed here, so the hosted Owner Action Queue was structurally empty
1186
+ // (AD-74 inverted). Now forwards; the edge binds user_id to the bearer ([C]).
1184
1187
  "recordContributorReleasePr",
1185
1188
  "setContributorReleasePrStatus",
1186
1189
  "listContributorReleasePrs",
package/dist/index.js CHANGED
@@ -1296,8 +1296,11 @@ var init_proxy_adapter = __esm({
1296
1296
  // (2) not-yet-wired hosted gaps — shrink as data-proxy handlers land (task-2390).
1297
1297
  // getToolCallCount + updatePhaseStatus are ABSENT: they now have edge handlers and
1298
1298
  // are served through the forwarder (getToolCallCount = SUP-2026-026 handler #1).
1299
- "createOwnerAction",
1300
1299
  "getContributorRole",
1300
+ // task-2728 (C331): createOwnerAction REMOVED from NO_FORWARD — the PRODUCER half
1301
+ // of the owner-action queue. Six readers were wired C329 (task-2412) but the
1302
+ // producer stayed here, so the hosted Owner Action Queue was structurally empty
1303
+ // (AD-74 inverted). Now forwards; the edge binds user_id to the bearer ([C]).
1301
1304
  "recordContributorReleasePr",
1302
1305
  "setContributorReleasePrStatus",
1303
1306
  "listContributorReleasePrs",
@@ -8169,20 +8172,27 @@ function formatDecisionLifecycleSummary(decisions) {
8169
8172
  }
8170
8173
  return parts.join(", ");
8171
8174
  }
8172
- function formatBuildReports(reports) {
8175
+ function formatBuildReports(reports, opts) {
8173
8176
  if (reports.length === 0) return "No build reports yet.";
8174
- return reports.map(
8177
+ const capped = opts?.maxReports != null ? reports.slice(0, opts.maxReports) : reports;
8178
+ const budget = opts?.fieldBudget;
8179
+ const field = (v) => budget != null ? truncateNotes(v, budget) : v ?? "";
8180
+ const body = capped.map(
8175
8181
  (r) => `### ${r.taskName} \u2014 ${r.date} \u2014 Cycle ${r.cycle}
8176
8182
 
8177
8183
  - **Completed:** ${r.completed}
8178
8184
  - **Actual Effort:** ${r.actualEffort} vs estimated ${r.estimatedEffort}
8179
8185
  ` + (r.correctionsCount ? `- **Corrections:** ${r.correctionsCount}
8180
8186
  ` : "") + (Array.isArray(r.briefImplications) && r.briefImplications.length ? `- **Brief Implications:** ${r.briefImplications.map((bi) => `[${bi.canvasSection}/${bi.type}] ${bi.detail}`).join("; ")}
8181
- ` : "") + `- **Surprises:** ${r.surprises}
8182
- - **Discovered Issues:** ${r.discoveredIssues}
8183
- - **Architecture Notes:** ${r.architectureNotes}` + (r.deadEnds ? `
8184
- - **Dead Ends:** ${r.deadEnds}` : "")
8187
+ ` : "") + `- **Surprises:** ${field(r.surprises)}
8188
+ - **Discovered Issues:** ${field(r.discoveredIssues)}
8189
+ - **Architecture Notes:** ${field(r.architectureNotes)}` + (r.deadEnds ? `
8190
+ - **Dead Ends:** ${field(r.deadEnds)}` : "")
8185
8191
  ).join("\n\n---\n\n");
8192
+ const omitted = capped.length < reports.length ? `
8193
+
8194
+ _\u2026and ${reports.length - capped.length} older build report(s) omitted to bound context size._` : "";
8195
+ return body + omitted;
8186
8196
  }
8187
8197
  function formatRecentlyShippedCapabilities(reports) {
8188
8198
  const completed = reports.filter((r) => r.completed === "Yes" || r.completed === "Partial");
@@ -8415,6 +8425,21 @@ function computeCycleEffort(cycleTaskRows, cycleReports) {
8415
8425
  function velocityPoints(v) {
8416
8426
  return v.deliveredPoints ?? v.effortPoints;
8417
8427
  }
8428
+ function resolveCompletedCycleDates(existingStart, earliestActivity, now) {
8429
+ const startDate = existingStart || earliestActivity || now;
8430
+ const startMs = Date.parse(startDate);
8431
+ const endMs = Date.parse(now);
8432
+ const known = Number.isFinite(startMs) && Number.isFinite(endMs) && startMs < endMs;
8433
+ return { startDate, endDate: known ? now : null };
8434
+ }
8435
+ function earliestCycleActivity(reports) {
8436
+ let earliest;
8437
+ for (const r of reports) {
8438
+ const ts = r.startedAt || r.createdAt || r.date;
8439
+ if (ts && (!earliest || Date.parse(ts) < Date.parse(earliest))) earliest = ts;
8440
+ }
8441
+ return earliest;
8442
+ }
8418
8443
  function computeSnapshotsFromBuildReports(reports, tasks) {
8419
8444
  const reportsByCycle = /* @__PURE__ */ new Map();
8420
8445
  for (const r of reports) {
@@ -8816,7 +8841,7 @@ PRE-BUILD VERIFICATION
8816
8841
  [List 2-5 specific file paths the builder should read BEFORE implementing to check if the functionality already exists. Derive these from FILES LIKELY TOUCHED \u2014 pick the files most likely to already contain the target functionality. ALSO mandate a docs sweep, not just file-existence (task-2161): name any docs the builder should check via doc_search or the docs index \u2014 a design/research/status:final doc or a prior task may already cover the work. If >80% of the scope is already implemented, the builder should report "already built" instead of re-implementing. Include this section for EVERY task \u2014 it prevents wasted build slots on already-shipped code.]
8817
8842
 
8818
8843
  FILES LIKELY TOUCHED
8819
- [files]
8844
+ [files \u2014 real paths only. TEST FILE LOCATIONS (task-2606): PAPI tests are NOT co-located next to source in a src/**/__tests__/ folder. Use the actual layout: server tests \u2192 packages/server/tests/<name>.test.ts; adapter-pg tests \u2192 packages/adapter-pg/src/__tests__/<name>.test.ts; dashboard/root tests \u2192 tests/<area>/<name>.test.ts. Do NOT invent packages/server/src/**/__tests__/ paths \u2014 they do not exist.]
8820
8845
 
8821
8846
  EFFORT
8822
8847
  [XS/S/M/L/XL]
@@ -9973,7 +9998,7 @@ REFERENCE DOCS
9973
9998
  [Optional \u2014 paths to docs/ files with background context. Omit if not needed.]
9974
9999
 
9975
10000
  FILES LIKELY TOUCHED
9976
- [files]
10001
+ [files \u2014 real paths only. TEST FILE LOCATIONS (task-2606): PAPI tests are NOT co-located next to source in a src/**/__tests__/ folder. Use the actual layout: server tests \u2192 packages/server/tests/<name>.test.ts; adapter-pg tests \u2192 packages/adapter-pg/src/__tests__/<name>.test.ts; dashboard/root tests \u2192 tests/<area>/<name>.test.ts. Do NOT invent packages/server/src/**/__tests__/ paths \u2014 they do not exist.]
9977
10002
 
9978
10003
  EFFORT
9979
10004
  [XS/S/M/L/XL]`;
@@ -10425,7 +10450,9 @@ async function prepareHandoffs(adapter2, _config, taskIds, force = false) {
10425
10450
  // buildHandoffsOnlyUserMessage adds +1 internally
10426
10451
  preAssignedTasks: tasksNeedingHandoffs,
10427
10452
  activeDecisions: formatActiveDecisionsForPlan(decisions),
10428
- recentBuildReports: formatBuildReports(reports),
10453
+ // task-2681: truncate verbose report bodies — a couple of audit reports alone
10454
+ // (e.g. task-2413/2655) can push this payload past the overflow range.
10455
+ recentBuildReports: formatBuildReports(reports, { maxReports: 10, fieldBudget: 280 }),
10429
10456
  productBrief: brief,
10430
10457
  northStar
10431
10458
  });
@@ -10946,6 +10973,7 @@ async function resolveOwnerGate(adapter2, config2) {
10946
10973
  }
10947
10974
 
10948
10975
  // src/services/plan.ts
10976
+ var PLAN_BUILD_REPORT_BUDGET = { maxReports: 12, fieldBudget: 280 };
10949
10977
  async function resolvePlanScope(adapter2, config2) {
10950
10978
  const gate = await resolveOwnerGate(adapter2, config2);
10951
10979
  return { callerUserId: gate.callerUserId, ownerUserId: gate.ownerUserId, callerIsOwner: gate.callerIsOwner };
@@ -11794,7 +11822,7 @@ ${logLines}`);
11794
11822
  cycleNumber: health.totalCycles,
11795
11823
  productBrief,
11796
11824
  activeDecisions: formatActiveDecisionsForPlan(decisions),
11797
- recentBuildReports: formatBuildReports(cappedReports),
11825
+ recentBuildReports: formatBuildReports(cappedReports, PLAN_BUILD_REPORT_BUDGET),
11798
11826
  cycleLog: formatCycleLog(log2),
11799
11827
  board: formatBoardForPlan(plannerTasks, filters, health.totalCycles, deferredTasks),
11800
11828
  northStar,
@@ -12580,7 +12608,7 @@ async function preparePlan(adapter2, config2, filters, focus, force, handoffsOnl
12580
12608
  cycleNumber,
12581
12609
  preAssignedTasks: preAssigned,
12582
12610
  activeDecisions: formatActiveDecisionsForPlan(decisions),
12583
- recentBuildReports: formatBuildReports(reports),
12611
+ recentBuildReports: formatBuildReports(reports, PLAN_BUILD_REPORT_BUDGET),
12584
12612
  productBrief: brief,
12585
12613
  northStar
12586
12614
  });
@@ -19043,20 +19071,11 @@ To override, pass force=true (emits a telemetry warning).`
19043
19071
  existing = (await adapter2.readCycles()).find((c) => c.number === currentCycle);
19044
19072
  } catch {
19045
19073
  }
19046
- const completedCycle = {
19047
- id: `cycle-${currentCycle}`,
19048
- number: currentCycle,
19049
- status: "complete",
19050
- startDate: existing?.startDate ?? (/* @__PURE__ */ new Date()).toISOString(),
19051
- endDate: (/* @__PURE__ */ new Date()).toISOString(),
19052
- goals: existing?.goals ?? [],
19053
- boardHealth: existing?.boardHealth ?? "",
19054
- taskIds: existing?.taskIds ?? []
19055
- };
19056
19074
  let snapshot;
19075
+ let cycleReports = [];
19057
19076
  if (adapter2.getBuildReportsSince) {
19058
19077
  try {
19059
- const cycleReports = (await adapter2.getBuildReportsSince(currentCycle)).filter((r) => r.cycle === currentCycle);
19078
+ cycleReports = (await adapter2.getBuildReportsSince(currentCycle)).filter((r) => r.cycle === currentCycle);
19060
19079
  const cycleTasks = (await adapter2.queryBoard({ cycleSince: currentCycle, compact: true })).filter((t) => t.cycle === currentCycle);
19061
19080
  [snapshot] = computeSnapshotsFromBuildReports(cycleReports, cycleTasks);
19062
19081
  } catch (err) {
@@ -19065,6 +19084,22 @@ To override, pass force=true (emits a telemetry warning).`
19065
19084
  );
19066
19085
  }
19067
19086
  }
19087
+ const releaseNow = (/* @__PURE__ */ new Date()).toISOString();
19088
+ const { startDate: resolvedStart, endDate: resolvedEnd } = resolveCompletedCycleDates(
19089
+ existing?.startDate,
19090
+ earliestCycleActivity(cycleReports),
19091
+ releaseNow
19092
+ );
19093
+ const completedCycle = {
19094
+ id: `cycle-${currentCycle}`,
19095
+ number: currentCycle,
19096
+ status: "complete",
19097
+ startDate: resolvedStart,
19098
+ endDate: resolvedEnd ?? void 0,
19099
+ goals: existing?.goals ?? [],
19100
+ boardHealth: existing?.boardHealth ?? "",
19101
+ taskIds: existing?.taskIds ?? []
19102
+ };
19068
19103
  if (typeof adapter2.commitRelease === "function") {
19069
19104
  try {
19070
19105
  await adapter2.commitRelease({ cycle: completedCycle, snapshot: snapshot ?? null });
@@ -20918,7 +20953,9 @@ async function completeBuild(adapter2, config2, taskId, input, options = {}, cli
20918
20953
  }
20919
20954
  }
20920
20955
  }
20956
+ const AUTO_TRIAGE_MIN_SEVERITY = /* @__PURE__ */ new Set(["P0", "P1", "P2"]);
20921
20957
  let autoTriagedCount = 0;
20958
+ let autoTriagedSoftSkipped = 0;
20922
20959
  const autoTriagedIds = [];
20923
20960
  const autoTriagedDupes = [];
20924
20961
  if (input.discoveredIssues && input.discoveredIssues !== "None" && typeof adapter2.createTask === "function") {
@@ -20938,6 +20975,10 @@ async function completeBuild(adapter2, config2, taskId, input, options = {}, cli
20938
20975
  const sevMatch = line.match(/^(P[0-3])[\s:]+/i);
20939
20976
  if (!sevMatch) continue;
20940
20977
  const severityLabel = sevMatch[1].toUpperCase();
20978
+ if (!AUTO_TRIAGE_MIN_SEVERITY.has(severityLabel)) {
20979
+ autoTriagedSoftSkipped++;
20980
+ continue;
20981
+ }
20941
20982
  const priority = severityLabel === "P0" ? "P0 Critical" : severityLabel === "P1" ? "P1 High" : severityLabel === "P2" ? "P2 Medium" : "P3 Low";
20942
20983
  const titleRaw = line.replace(/^P[0-3][\s:]+/i, "").trim();
20943
20984
  const title = titleRaw.length > 120 ? titleRaw.slice(0, 120) : titleRaw;
@@ -21187,6 +21228,7 @@ async function completeBuild(adapter2, config2, taskId, input, options = {}, cli
21187
21228
  autoTriagedCount: autoTriagedCount > 0 ? autoTriagedCount : void 0,
21188
21229
  autoTriagedIds: autoTriagedIds.length > 0 ? autoTriagedIds : void 0,
21189
21230
  autoTriagedDupes: autoTriagedDupes.length > 0 ? autoTriagedDupes : void 0,
21231
+ autoTriagedSoftSkipped: autoTriagedSoftSkipped > 0 ? autoTriagedSoftSkipped : void 0,
21190
21232
  reportWriteVerified,
21191
21233
  localPreview
21192
21234
  };
@@ -22300,7 +22342,7 @@ function formatCompleteResult(result) {
22300
22342
  if (result.learningsLinkedCount) {
22301
22343
  lines.push("", `Linked ${result.learningsLinkedCount} unactioned learning(s) to this task.`);
22302
22344
  }
22303
- if (result.autoTriagedCount || result.autoTriagedDupes?.length) {
22345
+ if (result.autoTriagedCount || result.autoTriagedDupes?.length || result.autoTriagedSoftSkipped) {
22304
22346
  const parts = [];
22305
22347
  if (result.autoTriagedCount) {
22306
22348
  const ids = result.autoTriagedIds?.length ? ` (${result.autoTriagedIds.join(", ")})` : "";
@@ -22309,6 +22351,9 @@ function formatCompleteResult(result) {
22309
22351
  if (result.autoTriagedDupes?.length) {
22310
22352
  parts.push(`Skipped ${result.autoTriagedDupes.length} duplicate issue(s) already in Backlog: ${result.autoTriagedDupes.join(", ")}.`);
22311
22353
  }
22354
+ if (result.autoTriagedSoftSkipped) {
22355
+ parts.push(`${result.autoTriagedSoftSkipped} low-severity (P3) observation(s) recorded to learnings, not filed as tasks.`);
22356
+ }
22312
22357
  lines.push("", parts.join(" "));
22313
22358
  }
22314
22359
  if (result.reportWriteVerified === false) {
@@ -25759,6 +25804,50 @@ function countStalledP1(warnings) {
25759
25804
  const matches = stallLine.match(/task-\d+/g);
25760
25805
  return matches ? matches.length : 0;
25761
25806
  }
25807
+ function truncateTaskTitle(title, max = 55) {
25808
+ const t = (title ?? "").trim();
25809
+ if (!t) return "untitled";
25810
+ if (t.length <= max) return t;
25811
+ return t.slice(0, max - 1).trimEnd() + "\u2026";
25812
+ }
25813
+ async function resolveCarryForwardRefs(carryForward, tasks, adapter2) {
25814
+ const refs = /* @__PURE__ */ new Map();
25815
+ const ids = carryForward?.match(/\btask-\d+\b/g);
25816
+ if (!ids) return refs;
25817
+ const unique = [...new Set(ids)];
25818
+ const byId = new Map(tasks.filter((t) => t.displayId).map((t) => [t.displayId, t]));
25819
+ const missing = [];
25820
+ for (const id of unique) {
25821
+ const t = byId.get(id);
25822
+ if (t) refs.set(id, { title: t.title, status: t.status });
25823
+ else missing.push(id);
25824
+ }
25825
+ if (missing.length > 0 && adapter2?.getTasks) {
25826
+ try {
25827
+ const fetched = await adapter2.getTasks(missing);
25828
+ for (const t of fetched) {
25829
+ if (t.displayId) refs.set(t.displayId, { title: t.title, status: t.status });
25830
+ }
25831
+ } catch {
25832
+ }
25833
+ }
25834
+ return refs;
25835
+ }
25836
+ function annotateTaskRefs(text, refs) {
25837
+ if (!text || refs.size === 0) return text;
25838
+ const RESOLVED = /* @__PURE__ */ new Set(["Done", "Cancelled"]);
25839
+ return text.replace(/\btask-\d+\b(?!\s*[(—–-])/g, (id, offset, full) => {
25840
+ const ref = refs.get(id);
25841
+ if (!ref) return id;
25842
+ const rest = full.slice(offset + id.length);
25843
+ if (/^\s*[(—–-]/.test(rest)) return id;
25844
+ const resolved = ref.status && RESOLVED.has(ref.status);
25845
+ const titlePart = ref.title ? ` \u2014 ${truncateTaskTitle(ref.title)}` : "";
25846
+ const statusPart = resolved ? ` [\u2713 ${ref.status}]` : "";
25847
+ if (!titlePart && !statusPart) return id;
25848
+ return `${id}${titlePart}${statusPart}`;
25849
+ });
25850
+ }
25762
25851
  function formatSynthesisParagraph(opts) {
25763
25852
  const parts = [];
25764
25853
  parts.push(
@@ -25778,7 +25867,7 @@ function formatSynthesisParagraph(opts) {
25778
25867
  parts.push(`Next: ${cleanMode}`);
25779
25868
  return parts.join(" ");
25780
25869
  }
25781
- function formatOrientSummary(health, buildInfo, hierarchy, latestTag, projectRoot, environment = "unknown", subAgents = [], projectName, teamSummary, clientName) {
25870
+ function formatOrientSummary(health, buildInfo, hierarchy, latestTag, projectRoot, environment = "unknown", subAgents = [], projectName, teamSummary, clientName, taskRefs = /* @__PURE__ */ new Map()) {
25782
25871
  const lines = [];
25783
25872
  const cycleIsComplete = health.latestCycleStatus === "complete";
25784
25873
  const tagSuffix = latestTag ? ` \u2014 ${latestTag}` : "";
@@ -25921,7 +26010,7 @@ function formatOrientSummary(health, buildInfo, hierarchy, latestTag, projectRoo
25921
26010
  const hasCarryForward = health.carryForward !== "None found" && !health.carryForward.startsWith("No carry-forward");
25922
26011
  if (hasCarryForward) {
25923
26012
  lines.push("## Carry-Forward");
25924
- lines.push(health.carryForward);
26013
+ lines.push(annotateTaskRefs(health.carryForward, taskRefs));
25925
26014
  lines.push("");
25926
26015
  }
25927
26016
  const hasMetrics = health.metricsSection !== "Could not read methodology metrics." && !health.metricsSection.includes("undefined");
@@ -26210,7 +26299,7 @@ async function handleOrient(adapter2, config2, args = {}, clientName) {
26210
26299
  (t) => t.createdCycle != null && currentCycle - t.createdCycle >= 3
26211
26300
  );
26212
26301
  if (stalledP1.length === 0) return void 0;
26213
- const ids = stalledP1.map((t) => `${t.displayId} (${currentCycle - (t.createdCycle ?? currentCycle)}+ cycles)`).join(", ");
26302
+ const ids = stalledP1.map((t) => `${t.displayId} \u2014 ${truncateTaskTitle(t.title)} (${currentCycle - (t.createdCycle ?? currentCycle)}+ cycles)`).join(", ");
26214
26303
  return `\u26A0\uFE0F P1 tasks stalled 3+ cycles: ${ids}`;
26215
26304
  }),
26216
26305
  // task-1917 (C280): Owner Action Queue surface. Counts the user's open
@@ -26228,10 +26317,12 @@ async function handleOrient(adapter2, config2, args = {}, clientName) {
26228
26317
  let dueSuffix = "";
26229
26318
  if (adapter2.countDueOwnerActions) {
26230
26319
  const due = await adapter2.countDueOwnerActions(userId, projectId);
26231
- const parts = [];
26232
- if (due.dueToday > 0) parts.push(`${due.dueToday} due today`);
26233
- if (due.overdue > 0) parts.push(`${due.overdue} overdue`);
26234
- if (parts.length > 0) dueSuffix = ` (${parts.join(", ")})`;
26320
+ if (due.urgent > 0) {
26321
+ const detail = [];
26322
+ if (due.overdue > 0) detail.push(`${due.overdue} overdue`);
26323
+ if (due.dueToday > 0) detail.push(`${due.dueToday} due today`);
26324
+ dueSuffix = detail.length > 0 ? ` (${due.urgent} need you now \u2014 ${detail.join(", ")})` : ` (${due.urgent} need you now)`;
26325
+ }
26235
26326
  }
26236
26327
  return `\u26A0\uFE0F ${count} action${count === 1 ? "" : "s"} waiting on you${dueSuffix} \u2014 open /hub to triage the Owner Action Queue.`;
26237
26328
  } catch {
@@ -26634,7 +26725,8 @@ ${section}`;
26634
26725
  ]);
26635
26726
  const teamSummary = [teamSummaryLine, releaseHistoryLine].filter(Boolean).join("\n") || void 0;
26636
26727
  const deepHint = deepHousekeeping ? "" : "\n\n*Tip: pass `full: true` for Research Signals + version-drift, or `deep_housekeeping: true` to also check orphaned branches, merged-but-In-Progress tasks, unrecorded commits, unregistered docs, and stale skill forks (implies `full`).*";
26637
- return textResponse(projectBannerNote + formatOrientSummary(healthResult, buildInfo, hierarchy, latestTag, config2.projectRoot, environment, subAgents, projectName, teamSummary, clientName) + unblockNote + deferredGateNote + feedbackResolvedNote + alertsNote + ttfvNote + reconciliationNote + mergedInProgressNote + unrecordedNote + unregisteredDocsNote + staleSkillsNote + researchSignalsNote + recsNote + pendingReviewNote + patternsNote + unactionedIssuesNote + skillProposalsNote + sessionGuidanceNote + versionNote + enrichmentNote + deliveryShapeNote + preBuildCheckNote + deepHint + enrichmentFilesSection);
26728
+ const carryForwardRefs = await resolveCarryForwardRefs(healthResult.carryForward, allTasks, adapter2);
26729
+ return textResponse(projectBannerNote + formatOrientSummary(healthResult, buildInfo, hierarchy, latestTag, config2.projectRoot, environment, subAgents, projectName, teamSummary, clientName, carryForwardRefs) + unblockNote + deferredGateNote + feedbackResolvedNote + alertsNote + ttfvNote + reconciliationNote + mergedInProgressNote + unrecordedNote + unregisteredDocsNote + staleSkillsNote + researchSignalsNote + recsNote + pendingReviewNote + patternsNote + unactionedIssuesNote + skillProposalsNote + sessionGuidanceNote + versionNote + enrichmentNote + deliveryShapeNote + preBuildCheckNote + deepHint + enrichmentFilesSection);
26638
26730
  } catch (err) {
26639
26731
  const message = err instanceof Error ? err.message : String(err);
26640
26732
  const isKnownFriendly = /^(Orient failed|Project not found|No project|Setup required)/i.test(message);
@@ -29064,9 +29156,11 @@ ${usageLine(decision.usage)}`;
29064
29156
  const clientName = server2.getClientVersion()?.name;
29065
29157
  const metric = buildMetric(name, elapsed, usage, void 0, contextBytes, contextUtilisation, clientName);
29066
29158
  metric.success = !isError;
29067
- adapter2.appendToolMetric(metric).catch(() => {
29159
+ adapter2.appendToolMetric(metric).catch((err) => {
29160
+ console.error(`[metrics] appendToolMetric failed (non-blocking): ${err instanceof Error ? err.message : String(err)}`);
29068
29161
  });
29069
- } catch {
29162
+ } catch (err) {
29163
+ console.error(`[metrics] buildMetric/appendToolMetric threw (non-blocking): ${err instanceof Error ? err.message : String(err)}`);
29070
29164
  }
29071
29165
  if (config2.adapterType === "md") {
29072
29166
  const mdProjectSlug = config2.projectRoot ? config2.projectRoot.split("/").pop() : void 0;
package/dist/prompts.js CHANGED
@@ -69,7 +69,7 @@ PRE-BUILD VERIFICATION
69
69
  [List 2-5 specific file paths the builder should read BEFORE implementing to check if the functionality already exists. Derive these from FILES LIKELY TOUCHED \u2014 pick the files most likely to already contain the target functionality. ALSO mandate a docs sweep, not just file-existence (task-2161): name any docs the builder should check via doc_search or the docs index \u2014 a design/research/status:final doc or a prior task may already cover the work. If >80% of the scope is already implemented, the builder should report "already built" instead of re-implementing. Include this section for EVERY task \u2014 it prevents wasted build slots on already-shipped code.]
70
70
 
71
71
  FILES LIKELY TOUCHED
72
- [files]
72
+ [files \u2014 real paths only. TEST FILE LOCATIONS (task-2606): PAPI tests are NOT co-located next to source in a src/**/__tests__/ folder. Use the actual layout: server tests \u2192 packages/server/tests/<name>.test.ts; adapter-pg tests \u2192 packages/adapter-pg/src/__tests__/<name>.test.ts; dashboard/root tests \u2192 tests/<area>/<name>.test.ts. Do NOT invent packages/server/src/**/__tests__/ paths \u2014 they do not exist.]
73
73
 
74
74
  EFFORT
75
75
  [XS/S/M/L/XL]
@@ -1226,7 +1226,7 @@ REFERENCE DOCS
1226
1226
  [Optional \u2014 paths to docs/ files with background context. Omit if not needed.]
1227
1227
 
1228
1228
  FILES LIKELY TOUCHED
1229
- [files]
1229
+ [files \u2014 real paths only. TEST FILE LOCATIONS (task-2606): PAPI tests are NOT co-located next to source in a src/**/__tests__/ folder. Use the actual layout: server tests \u2192 packages/server/tests/<name>.test.ts; adapter-pg tests \u2192 packages/adapter-pg/src/__tests__/<name>.test.ts; dashboard/root tests \u2192 tests/<area>/<name>.test.ts. Do NOT invent packages/server/src/**/__tests__/ paths \u2014 they do not exist.]
1230
1230
 
1231
1231
  EFFORT
1232
1232
  [XS/S/M/L/XL]`;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@papi-ai/server",
3
- "version": "0.7.55",
4
- "description": "PAPI MCP server AI-powered sprint planning, build execution, and strategy review for software projects",
3
+ "version": "0.7.57",
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",
7
7
  "type": "module",