@papi-ai/server 0.7.56 → 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.
- package/dist/index.js +90 -21
- package/dist/prompts.js +2 -2
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -8425,6 +8425,21 @@ function computeCycleEffort(cycleTaskRows, cycleReports) {
|
|
|
8425
8425
|
function velocityPoints(v) {
|
|
8426
8426
|
return v.deliveredPoints ?? v.effortPoints;
|
|
8427
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
|
+
}
|
|
8428
8443
|
function computeSnapshotsFromBuildReports(reports, tasks) {
|
|
8429
8444
|
const reportsByCycle = /* @__PURE__ */ new Map();
|
|
8430
8445
|
for (const r of reports) {
|
|
@@ -8826,7 +8841,7 @@ PRE-BUILD VERIFICATION
|
|
|
8826
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.]
|
|
8827
8842
|
|
|
8828
8843
|
FILES LIKELY TOUCHED
|
|
8829
|
-
[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.]
|
|
8830
8845
|
|
|
8831
8846
|
EFFORT
|
|
8832
8847
|
[XS/S/M/L/XL]
|
|
@@ -9983,7 +9998,7 @@ REFERENCE DOCS
|
|
|
9983
9998
|
[Optional \u2014 paths to docs/ files with background context. Omit if not needed.]
|
|
9984
9999
|
|
|
9985
10000
|
FILES LIKELY TOUCHED
|
|
9986
|
-
[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.]
|
|
9987
10002
|
|
|
9988
10003
|
EFFORT
|
|
9989
10004
|
[XS/S/M/L/XL]`;
|
|
@@ -19056,20 +19071,11 @@ To override, pass force=true (emits a telemetry warning).`
|
|
|
19056
19071
|
existing = (await adapter2.readCycles()).find((c) => c.number === currentCycle);
|
|
19057
19072
|
} catch {
|
|
19058
19073
|
}
|
|
19059
|
-
const completedCycle = {
|
|
19060
|
-
id: `cycle-${currentCycle}`,
|
|
19061
|
-
number: currentCycle,
|
|
19062
|
-
status: "complete",
|
|
19063
|
-
startDate: existing?.startDate ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
19064
|
-
endDate: (/* @__PURE__ */ new Date()).toISOString(),
|
|
19065
|
-
goals: existing?.goals ?? [],
|
|
19066
|
-
boardHealth: existing?.boardHealth ?? "",
|
|
19067
|
-
taskIds: existing?.taskIds ?? []
|
|
19068
|
-
};
|
|
19069
19074
|
let snapshot;
|
|
19075
|
+
let cycleReports = [];
|
|
19070
19076
|
if (adapter2.getBuildReportsSince) {
|
|
19071
19077
|
try {
|
|
19072
|
-
|
|
19078
|
+
cycleReports = (await adapter2.getBuildReportsSince(currentCycle)).filter((r) => r.cycle === currentCycle);
|
|
19073
19079
|
const cycleTasks = (await adapter2.queryBoard({ cycleSince: currentCycle, compact: true })).filter((t) => t.cycle === currentCycle);
|
|
19074
19080
|
[snapshot] = computeSnapshotsFromBuildReports(cycleReports, cycleTasks);
|
|
19075
19081
|
} catch (err) {
|
|
@@ -19078,6 +19084,22 @@ To override, pass force=true (emits a telemetry warning).`
|
|
|
19078
19084
|
);
|
|
19079
19085
|
}
|
|
19080
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
|
+
};
|
|
19081
19103
|
if (typeof adapter2.commitRelease === "function") {
|
|
19082
19104
|
try {
|
|
19083
19105
|
await adapter2.commitRelease({ cycle: completedCycle, snapshot: snapshot ?? null });
|
|
@@ -25782,6 +25804,50 @@ function countStalledP1(warnings) {
|
|
|
25782
25804
|
const matches = stallLine.match(/task-\d+/g);
|
|
25783
25805
|
return matches ? matches.length : 0;
|
|
25784
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
|
+
}
|
|
25785
25851
|
function formatSynthesisParagraph(opts) {
|
|
25786
25852
|
const parts = [];
|
|
25787
25853
|
parts.push(
|
|
@@ -25801,7 +25867,7 @@ function formatSynthesisParagraph(opts) {
|
|
|
25801
25867
|
parts.push(`Next: ${cleanMode}`);
|
|
25802
25868
|
return parts.join(" ");
|
|
25803
25869
|
}
|
|
25804
|
-
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()) {
|
|
25805
25871
|
const lines = [];
|
|
25806
25872
|
const cycleIsComplete = health.latestCycleStatus === "complete";
|
|
25807
25873
|
const tagSuffix = latestTag ? ` \u2014 ${latestTag}` : "";
|
|
@@ -25944,7 +26010,7 @@ function formatOrientSummary(health, buildInfo, hierarchy, latestTag, projectRoo
|
|
|
25944
26010
|
const hasCarryForward = health.carryForward !== "None found" && !health.carryForward.startsWith("No carry-forward");
|
|
25945
26011
|
if (hasCarryForward) {
|
|
25946
26012
|
lines.push("## Carry-Forward");
|
|
25947
|
-
lines.push(health.carryForward);
|
|
26013
|
+
lines.push(annotateTaskRefs(health.carryForward, taskRefs));
|
|
25948
26014
|
lines.push("");
|
|
25949
26015
|
}
|
|
25950
26016
|
const hasMetrics = health.metricsSection !== "Could not read methodology metrics." && !health.metricsSection.includes("undefined");
|
|
@@ -26233,7 +26299,7 @@ async function handleOrient(adapter2, config2, args = {}, clientName) {
|
|
|
26233
26299
|
(t) => t.createdCycle != null && currentCycle - t.createdCycle >= 3
|
|
26234
26300
|
);
|
|
26235
26301
|
if (stalledP1.length === 0) return void 0;
|
|
26236
|
-
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(", ");
|
|
26237
26303
|
return `\u26A0\uFE0F P1 tasks stalled 3+ cycles: ${ids}`;
|
|
26238
26304
|
}),
|
|
26239
26305
|
// task-1917 (C280): Owner Action Queue surface. Counts the user's open
|
|
@@ -26251,10 +26317,12 @@ async function handleOrient(adapter2, config2, args = {}, clientName) {
|
|
|
26251
26317
|
let dueSuffix = "";
|
|
26252
26318
|
if (adapter2.countDueOwnerActions) {
|
|
26253
26319
|
const due = await adapter2.countDueOwnerActions(userId, projectId);
|
|
26254
|
-
|
|
26255
|
-
|
|
26256
|
-
|
|
26257
|
-
|
|
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
|
+
}
|
|
26258
26326
|
}
|
|
26259
26327
|
return `\u26A0\uFE0F ${count} action${count === 1 ? "" : "s"} waiting on you${dueSuffix} \u2014 open /hub to triage the Owner Action Queue.`;
|
|
26260
26328
|
} catch {
|
|
@@ -26657,7 +26725,8 @@ ${section}`;
|
|
|
26657
26725
|
]);
|
|
26658
26726
|
const teamSummary = [teamSummaryLine, releaseHistoryLine].filter(Boolean).join("\n") || void 0;
|
|
26659
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`).*";
|
|
26660
|
-
|
|
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);
|
|
26661
26730
|
} catch (err) {
|
|
26662
26731
|
const message = err instanceof Error ? err.message : String(err);
|
|
26663
26732
|
const isKnownFriendly = /^(Orient failed|Project not found|No project|Setup required)/i.test(message);
|
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.
|
|
4
|
-
"description": "PAPI MCP server
|
|
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",
|