@papi-ai/server 0.7.56 → 0.7.58
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 +132 -27
- package/dist/prompts.js +10 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8081,7 +8081,9 @@ import {
|
|
|
8081
8081
|
// src/universal-frame.ts
|
|
8082
8082
|
var UNIVERSAL_FRAME = `PAPI gives this project a structured plan \u2192 build \u2192 review cycle, persisted across sessions. Follow it:
|
|
8083
8083
|
|
|
8084
|
-
|
|
8084
|
+
0. NEW HERE? If PAPI has never been set up for this project (no cycles yet, or \`orient\` says the board is empty), call \`setup\` FIRST \u2014 it generates the Product Brief and scaffolds the workflow. Then run \`plan\` to create the first cycle. This is the required first step for a brand-new project; everything below assumes setup has already run.
|
|
8085
|
+
|
|
8086
|
+
1. ORIENT FIRST (once set up). At the start of every session, call \`orient\` (or \`papi\`) before anything else \u2014 it returns the current cycle, what's in flight, and the recommended next action. Re-run it after any context compression.
|
|
8085
8087
|
|
|
8086
8088
|
2. THE CYCLE, IN ORDER: \`plan\` (once per cycle) \u2192 \`build_list\` (pick a task) \u2192 \`build_execute <task>\` to start \u2192 implement the task from its BUILD HANDOFF \u2192 \`build_execute\` again to complete with a build report \u2192 \`review_submit\` \u2192 \`release\` when every cycle task is done.
|
|
8087
8089
|
|
|
@@ -8425,6 +8427,21 @@ function computeCycleEffort(cycleTaskRows, cycleReports) {
|
|
|
8425
8427
|
function velocityPoints(v) {
|
|
8426
8428
|
return v.deliveredPoints ?? v.effortPoints;
|
|
8427
8429
|
}
|
|
8430
|
+
function resolveCompletedCycleDates(existingStart, earliestActivity, now) {
|
|
8431
|
+
const startDate = existingStart || earliestActivity || now;
|
|
8432
|
+
const startMs = Date.parse(startDate);
|
|
8433
|
+
const endMs = Date.parse(now);
|
|
8434
|
+
const known = Number.isFinite(startMs) && Number.isFinite(endMs) && startMs < endMs;
|
|
8435
|
+
return { startDate, endDate: known ? now : null };
|
|
8436
|
+
}
|
|
8437
|
+
function earliestCycleActivity(reports) {
|
|
8438
|
+
let earliest;
|
|
8439
|
+
for (const r of reports) {
|
|
8440
|
+
const ts = r.startedAt || r.createdAt || r.date;
|
|
8441
|
+
if (ts && (!earliest || Date.parse(ts) < Date.parse(earliest))) earliest = ts;
|
|
8442
|
+
}
|
|
8443
|
+
return earliest;
|
|
8444
|
+
}
|
|
8428
8445
|
function computeSnapshotsFromBuildReports(reports, tasks) {
|
|
8429
8446
|
const reportsByCycle = /* @__PURE__ */ new Map();
|
|
8430
8447
|
for (const r of reports) {
|
|
@@ -8826,7 +8843,7 @@ PRE-BUILD VERIFICATION
|
|
|
8826
8843
|
[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
8844
|
|
|
8828
8845
|
FILES LIKELY TOUCHED
|
|
8829
|
-
[files]
|
|
8846
|
+
[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
8847
|
|
|
8831
8848
|
EFFORT
|
|
8832
8849
|
[XS/S/M/L/XL]
|
|
@@ -9286,7 +9303,14 @@ function buildPlanUserMessage(ctx) {
|
|
|
9286
9303
|
parts.push("### Pre-Assigned Tasks", "", ctx.preAssignedTasks, "");
|
|
9287
9304
|
}
|
|
9288
9305
|
if (ctx.codebaseScan) {
|
|
9289
|
-
parts.push(
|
|
9306
|
+
parts.push(
|
|
9307
|
+
"### Codebase Scan (existing implementations)",
|
|
9308
|
+
"",
|
|
9309
|
+
"Any task tagged **PREMISE-UNVERIFIED** is a discovery/auto-triaged item whose premise references code that already exists \u2014 before scheduling it, verify the premise still holds against the live code; if it is already resolved, deprioritise or cancel it rather than spending a build slot re-verifying shipped work.",
|
|
9310
|
+
"",
|
|
9311
|
+
ctx.codebaseScan,
|
|
9312
|
+
""
|
|
9313
|
+
);
|
|
9290
9314
|
}
|
|
9291
9315
|
if (ctx.buildPatterns) {
|
|
9292
9316
|
parts.push("### Build Patterns", "", ctx.buildPatterns, "");
|
|
@@ -9983,7 +10007,7 @@ REFERENCE DOCS
|
|
|
9983
10007
|
[Optional \u2014 paths to docs/ files with background context. Omit if not needed.]
|
|
9984
10008
|
|
|
9985
10009
|
FILES LIKELY TOUCHED
|
|
9986
|
-
[files]
|
|
10010
|
+
[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
10011
|
|
|
9988
10012
|
EFFORT
|
|
9989
10013
|
[XS/S/M/L/XL]`;
|
|
@@ -10699,6 +10723,10 @@ function extractSearchTerms(title, notes) {
|
|
|
10699
10723
|
}
|
|
10700
10724
|
return terms.slice(0, 8);
|
|
10701
10725
|
}
|
|
10726
|
+
function isDiscoveryTask(task) {
|
|
10727
|
+
if (task.taskType === "discovery") return true;
|
|
10728
|
+
return /^\s*\[auto-triaged\]/i.test(task.title);
|
|
10729
|
+
}
|
|
10702
10730
|
function grepForTerm(projectRoot, term) {
|
|
10703
10731
|
try {
|
|
10704
10732
|
const result = execSync2(
|
|
@@ -10732,19 +10760,24 @@ function scanCodebaseForTasks(projectRoot, tasks) {
|
|
|
10732
10760
|
}
|
|
10733
10761
|
}
|
|
10734
10762
|
if (matches.length > 0) {
|
|
10735
|
-
results.push({ taskId: task.id, terms, matches });
|
|
10763
|
+
results.push({ taskId: task.id, terms, matches, premiseUnverified: isDiscoveryTask(task) });
|
|
10736
10764
|
}
|
|
10737
10765
|
if (Date.now() - startTime > 5e3) break;
|
|
10738
10766
|
}
|
|
10739
10767
|
if (results.length === 0) return "";
|
|
10740
10768
|
const elapsed = Date.now() - startTime;
|
|
10741
10769
|
console.error(`[codebase-scan] scanned ${tasks.length} tasks in ${elapsed}ms \u2014 ${results.length} with matches`);
|
|
10770
|
+
const flaggedCount = results.filter((r) => r.premiseUnverified).length;
|
|
10771
|
+
const flagNote = flaggedCount > 0 ? ` \u2014 ${flaggedCount} discovery/auto-triaged task(s) flagged PREMISE-UNVERIFIED (verify before scheduling)` : "";
|
|
10742
10772
|
const lines = [
|
|
10743
|
-
`Codebase scan found existing implementations for ${results.length}/${tasks.length} candidate tasks (${elapsed}ms):`,
|
|
10773
|
+
`Codebase scan found existing implementations for ${results.length}/${tasks.length} candidate tasks (${elapsed}ms)${flagNote}:`,
|
|
10744
10774
|
""
|
|
10745
10775
|
];
|
|
10746
10776
|
for (const result of results) {
|
|
10747
10777
|
lines.push(`**${result.taskId}:**`);
|
|
10778
|
+
if (result.premiseUnverified) {
|
|
10779
|
+
lines.push(` \u26A0 PREMISE-UNVERIFIED: discovery/auto-triaged task whose premise references code already present in the repo \u2014 verify the premise still holds; it may already be resolved.`);
|
|
10780
|
+
}
|
|
10748
10781
|
for (const match of result.matches.slice(0, 3)) {
|
|
10749
10782
|
const fileList = match.files.slice(0, 3).join(", ");
|
|
10750
10783
|
const moreCount = match.files.length > 3 ? ` (+${match.files.length - 3} more)` : "";
|
|
@@ -12628,7 +12661,7 @@ async function preparePlan(adapter2, config2, filters, focus, force, handoffsOnl
|
|
|
12628
12661
|
t = startTimer();
|
|
12629
12662
|
try {
|
|
12630
12663
|
const scanTasks = await adapter2.queryBoard({ status: ["Backlog", "In Cycle", "Ready"], compact: true });
|
|
12631
|
-
const candidates = scanTasks.filter((task) => task.priority !== "P3 Low" && task.scopeClass !== "brief").slice(0, 15).map((task) => ({ id: task.id, title: task.title, notes: task.notes }));
|
|
12664
|
+
const candidates = scanTasks.filter((task) => task.priority !== "P3 Low" && task.scopeClass !== "brief").slice(0, 15).map((task) => ({ id: task.id, title: task.title, notes: task.notes, taskType: task.taskType }));
|
|
12632
12665
|
const scanResult = scanCodebaseForTasks(config2.projectRoot, candidates);
|
|
12633
12666
|
if (scanResult) context.codebaseScan = scanResult;
|
|
12634
12667
|
} catch (err) {
|
|
@@ -18815,6 +18848,7 @@ init_telemetry();
|
|
|
18815
18848
|
import { writeFile as writeFile3, readFile as readFile5 } from "fs/promises";
|
|
18816
18849
|
import { join as join10 } from "path";
|
|
18817
18850
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
18851
|
+
import { isSensitiveChangelogLine } from "@papi-ai/shared";
|
|
18818
18852
|
init_git();
|
|
18819
18853
|
var INITIAL_RELEASE_NOTES = `# Changelog
|
|
18820
18854
|
|
|
@@ -18826,7 +18860,9 @@ All notable changes to this project are documented in this file.
|
|
|
18826
18860
|
`;
|
|
18827
18861
|
function generateChangelogSection(version, commits) {
|
|
18828
18862
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
18829
|
-
const filtered = commits.filter(
|
|
18863
|
+
const filtered = commits.filter(
|
|
18864
|
+
(c) => !new RegExp(`^[a-f0-9]+ release: ${version}$`).test(c) && !isSensitiveChangelogLine(c)
|
|
18865
|
+
);
|
|
18830
18866
|
const commitList = filtered.map((c) => `- ${c}`).join("\n");
|
|
18831
18867
|
return `## ${version} \u2014 ${date}
|
|
18832
18868
|
|
|
@@ -19056,20 +19092,11 @@ To override, pass force=true (emits a telemetry warning).`
|
|
|
19056
19092
|
existing = (await adapter2.readCycles()).find((c) => c.number === currentCycle);
|
|
19057
19093
|
} catch {
|
|
19058
19094
|
}
|
|
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
19095
|
let snapshot;
|
|
19096
|
+
let cycleReports = [];
|
|
19070
19097
|
if (adapter2.getBuildReportsSince) {
|
|
19071
19098
|
try {
|
|
19072
|
-
|
|
19099
|
+
cycleReports = (await adapter2.getBuildReportsSince(currentCycle)).filter((r) => r.cycle === currentCycle);
|
|
19073
19100
|
const cycleTasks = (await adapter2.queryBoard({ cycleSince: currentCycle, compact: true })).filter((t) => t.cycle === currentCycle);
|
|
19074
19101
|
[snapshot] = computeSnapshotsFromBuildReports(cycleReports, cycleTasks);
|
|
19075
19102
|
} catch (err) {
|
|
@@ -19078,6 +19105,22 @@ To override, pass force=true (emits a telemetry warning).`
|
|
|
19078
19105
|
);
|
|
19079
19106
|
}
|
|
19080
19107
|
}
|
|
19108
|
+
const releaseNow = (/* @__PURE__ */ new Date()).toISOString();
|
|
19109
|
+
const { startDate: resolvedStart, endDate: resolvedEnd } = resolveCompletedCycleDates(
|
|
19110
|
+
existing?.startDate,
|
|
19111
|
+
earliestCycleActivity(cycleReports),
|
|
19112
|
+
releaseNow
|
|
19113
|
+
);
|
|
19114
|
+
const completedCycle = {
|
|
19115
|
+
id: `cycle-${currentCycle}`,
|
|
19116
|
+
number: currentCycle,
|
|
19117
|
+
status: "complete",
|
|
19118
|
+
startDate: resolvedStart,
|
|
19119
|
+
endDate: resolvedEnd ?? void 0,
|
|
19120
|
+
goals: existing?.goals ?? [],
|
|
19121
|
+
boardHealth: existing?.boardHealth ?? "",
|
|
19122
|
+
taskIds: existing?.taskIds ?? []
|
|
19123
|
+
};
|
|
19081
19124
|
if (typeof adapter2.commitRelease === "function") {
|
|
19082
19125
|
try {
|
|
19083
19126
|
await adapter2.commitRelease({ cycle: completedCycle, snapshot: snapshot ?? null });
|
|
@@ -25782,6 +25825,50 @@ function countStalledP1(warnings) {
|
|
|
25782
25825
|
const matches = stallLine.match(/task-\d+/g);
|
|
25783
25826
|
return matches ? matches.length : 0;
|
|
25784
25827
|
}
|
|
25828
|
+
function truncateTaskTitle(title, max = 55) {
|
|
25829
|
+
const t = (title ?? "").trim();
|
|
25830
|
+
if (!t) return "untitled";
|
|
25831
|
+
if (t.length <= max) return t;
|
|
25832
|
+
return t.slice(0, max - 1).trimEnd() + "\u2026";
|
|
25833
|
+
}
|
|
25834
|
+
async function resolveCarryForwardRefs(carryForward, tasks, adapter2) {
|
|
25835
|
+
const refs = /* @__PURE__ */ new Map();
|
|
25836
|
+
const ids = carryForward?.match(/\btask-\d+\b/g);
|
|
25837
|
+
if (!ids) return refs;
|
|
25838
|
+
const unique = [...new Set(ids)];
|
|
25839
|
+
const byId = new Map(tasks.filter((t) => t.displayId).map((t) => [t.displayId, t]));
|
|
25840
|
+
const missing = [];
|
|
25841
|
+
for (const id of unique) {
|
|
25842
|
+
const t = byId.get(id);
|
|
25843
|
+
if (t) refs.set(id, { title: t.title, status: t.status });
|
|
25844
|
+
else missing.push(id);
|
|
25845
|
+
}
|
|
25846
|
+
if (missing.length > 0 && adapter2?.getTasks) {
|
|
25847
|
+
try {
|
|
25848
|
+
const fetched = await adapter2.getTasks(missing);
|
|
25849
|
+
for (const t of fetched) {
|
|
25850
|
+
if (t.displayId) refs.set(t.displayId, { title: t.title, status: t.status });
|
|
25851
|
+
}
|
|
25852
|
+
} catch {
|
|
25853
|
+
}
|
|
25854
|
+
}
|
|
25855
|
+
return refs;
|
|
25856
|
+
}
|
|
25857
|
+
function annotateTaskRefs(text, refs) {
|
|
25858
|
+
if (!text || refs.size === 0) return text;
|
|
25859
|
+
const RESOLVED = /* @__PURE__ */ new Set(["Done", "Cancelled"]);
|
|
25860
|
+
return text.replace(/\btask-\d+\b(?!\s*[(—–-])/g, (id, offset, full) => {
|
|
25861
|
+
const ref = refs.get(id);
|
|
25862
|
+
if (!ref) return id;
|
|
25863
|
+
const rest = full.slice(offset + id.length);
|
|
25864
|
+
if (/^\s*[(—–-]/.test(rest)) return id;
|
|
25865
|
+
const resolved = ref.status && RESOLVED.has(ref.status);
|
|
25866
|
+
const titlePart = ref.title ? ` \u2014 ${truncateTaskTitle(ref.title)}` : "";
|
|
25867
|
+
const statusPart = resolved ? ` [\u2713 ${ref.status}]` : "";
|
|
25868
|
+
if (!titlePart && !statusPart) return id;
|
|
25869
|
+
return `${id}${titlePart}${statusPart}`;
|
|
25870
|
+
});
|
|
25871
|
+
}
|
|
25785
25872
|
function formatSynthesisParagraph(opts) {
|
|
25786
25873
|
const parts = [];
|
|
25787
25874
|
parts.push(
|
|
@@ -25801,7 +25888,7 @@ function formatSynthesisParagraph(opts) {
|
|
|
25801
25888
|
parts.push(`Next: ${cleanMode}`);
|
|
25802
25889
|
return parts.join(" ");
|
|
25803
25890
|
}
|
|
25804
|
-
function formatOrientSummary(health, buildInfo, hierarchy, latestTag, projectRoot, environment = "unknown", subAgents = [], projectName, teamSummary, clientName) {
|
|
25891
|
+
function formatOrientSummary(health, buildInfo, hierarchy, latestTag, projectRoot, environment = "unknown", subAgents = [], projectName, teamSummary, clientName, taskRefs = /* @__PURE__ */ new Map()) {
|
|
25805
25892
|
const lines = [];
|
|
25806
25893
|
const cycleIsComplete = health.latestCycleStatus === "complete";
|
|
25807
25894
|
const tagSuffix = latestTag ? ` \u2014 ${latestTag}` : "";
|
|
@@ -25944,7 +26031,7 @@ function formatOrientSummary(health, buildInfo, hierarchy, latestTag, projectRoo
|
|
|
25944
26031
|
const hasCarryForward = health.carryForward !== "None found" && !health.carryForward.startsWith("No carry-forward");
|
|
25945
26032
|
if (hasCarryForward) {
|
|
25946
26033
|
lines.push("## Carry-Forward");
|
|
25947
|
-
lines.push(health.carryForward);
|
|
26034
|
+
lines.push(annotateTaskRefs(health.carryForward, taskRefs));
|
|
25948
26035
|
lines.push("");
|
|
25949
26036
|
}
|
|
25950
26037
|
const hasMetrics = health.metricsSection !== "Could not read methodology metrics." && !health.metricsSection.includes("undefined");
|
|
@@ -26233,7 +26320,7 @@ async function handleOrient(adapter2, config2, args = {}, clientName) {
|
|
|
26233
26320
|
(t) => t.createdCycle != null && currentCycle - t.createdCycle >= 3
|
|
26234
26321
|
);
|
|
26235
26322
|
if (stalledP1.length === 0) return void 0;
|
|
26236
|
-
const ids = stalledP1.map((t) => `${t.displayId} (${currentCycle - (t.createdCycle ?? currentCycle)}+ cycles)`).join(", ");
|
|
26323
|
+
const ids = stalledP1.map((t) => `${t.displayId} \u2014 ${truncateTaskTitle(t.title)} (${currentCycle - (t.createdCycle ?? currentCycle)}+ cycles)`).join(", ");
|
|
26237
26324
|
return `\u26A0\uFE0F P1 tasks stalled 3+ cycles: ${ids}`;
|
|
26238
26325
|
}),
|
|
26239
26326
|
// task-1917 (C280): Owner Action Queue surface. Counts the user's open
|
|
@@ -26251,10 +26338,12 @@ async function handleOrient(adapter2, config2, args = {}, clientName) {
|
|
|
26251
26338
|
let dueSuffix = "";
|
|
26252
26339
|
if (adapter2.countDueOwnerActions) {
|
|
26253
26340
|
const due = await adapter2.countDueOwnerActions(userId, projectId);
|
|
26254
|
-
|
|
26255
|
-
|
|
26256
|
-
|
|
26257
|
-
|
|
26341
|
+
if (due.urgent > 0) {
|
|
26342
|
+
const detail = [];
|
|
26343
|
+
if (due.overdue > 0) detail.push(`${due.overdue} overdue`);
|
|
26344
|
+
if (due.dueToday > 0) detail.push(`${due.dueToday} due today`);
|
|
26345
|
+
dueSuffix = detail.length > 0 ? ` (${due.urgent} need you now \u2014 ${detail.join(", ")})` : ` (${due.urgent} need you now)`;
|
|
26346
|
+
}
|
|
26258
26347
|
}
|
|
26259
26348
|
return `\u26A0\uFE0F ${count} action${count === 1 ? "" : "s"} waiting on you${dueSuffix} \u2014 open /hub to triage the Owner Action Queue.`;
|
|
26260
26349
|
} catch {
|
|
@@ -26657,7 +26746,8 @@ ${section}`;
|
|
|
26657
26746
|
]);
|
|
26658
26747
|
const teamSummary = [teamSummaryLine, releaseHistoryLine].filter(Boolean).join("\n") || void 0;
|
|
26659
26748
|
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
|
-
|
|
26749
|
+
const carryForwardRefs = await resolveCarryForwardRefs(healthResult.carryForward, allTasks, adapter2);
|
|
26750
|
+
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
26751
|
} catch (err) {
|
|
26662
26752
|
const message = err instanceof Error ? err.message : String(err);
|
|
26663
26753
|
const isKnownFriendly = /^(Orient failed|Project not found|No project|Setup required)/i.test(message);
|
|
@@ -29143,6 +29233,7 @@ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/
|
|
|
29143
29233
|
var BEARER_PREFIX = "papi_";
|
|
29144
29234
|
var BEARER_REGEX = /^(papi_|papi_oauth_)[a-f0-9]{64}$/;
|
|
29145
29235
|
var RESOURCE_METADATA_URL = process.env["PAPI_RESOURCE_METADATA_URL"] ?? "https://getpapi.ai/.well-known/oauth-protected-resource";
|
|
29236
|
+
var GLAMA_MAINTAINER_EMAIL = process.env["GLAMA_MAINTAINER_EMAIL"] ?? "cathal@getpapi.ai";
|
|
29146
29237
|
var DASHBOARD_ORIGIN = process.env["PAPI_DASHBOARD_URL"] ?? "https://getpapi.ai";
|
|
29147
29238
|
var MCP_RESOURCE_URL = process.env["NEXT_PUBLIC_MCP_URL"] ?? "https://mcp.getpapi.ai";
|
|
29148
29239
|
var FRIENDLY_GET_HTML = `<!doctype html>
|
|
@@ -29288,6 +29379,20 @@ function startHttpTransport(opts) {
|
|
|
29288
29379
|
);
|
|
29289
29380
|
return;
|
|
29290
29381
|
}
|
|
29382
|
+
if (req.method === "GET" && req.url === "/.well-known/glama.json") {
|
|
29383
|
+
res.writeHead(200, {
|
|
29384
|
+
"Content-Type": "application/json",
|
|
29385
|
+
"Cache-Control": "public, max-age=3600",
|
|
29386
|
+
...cors
|
|
29387
|
+
});
|
|
29388
|
+
res.end(
|
|
29389
|
+
JSON.stringify({
|
|
29390
|
+
$schema: "https://glama.ai/mcp/schemas/connector.json",
|
|
29391
|
+
maintainers: [{ email: GLAMA_MAINTAINER_EMAIL }]
|
|
29392
|
+
})
|
|
29393
|
+
);
|
|
29394
|
+
return;
|
|
29395
|
+
}
|
|
29291
29396
|
if (req.method === "GET" && req.url === "/.well-known/oauth-authorization-server") {
|
|
29292
29397
|
res.writeHead(302, {
|
|
29293
29398
|
Location: `${DASHBOARD_ORIGIN}/.well-known/oauth-authorization-server`,
|
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]
|
|
@@ -529,7 +529,14 @@ function buildPlanUserMessage(ctx) {
|
|
|
529
529
|
parts.push("### Pre-Assigned Tasks", "", ctx.preAssignedTasks, "");
|
|
530
530
|
}
|
|
531
531
|
if (ctx.codebaseScan) {
|
|
532
|
-
parts.push(
|
|
532
|
+
parts.push(
|
|
533
|
+
"### Codebase Scan (existing implementations)",
|
|
534
|
+
"",
|
|
535
|
+
"Any task tagged **PREMISE-UNVERIFIED** is a discovery/auto-triaged item whose premise references code that already exists \u2014 before scheduling it, verify the premise still holds against the live code; if it is already resolved, deprioritise or cancel it rather than spending a build slot re-verifying shipped work.",
|
|
536
|
+
"",
|
|
537
|
+
ctx.codebaseScan,
|
|
538
|
+
""
|
|
539
|
+
);
|
|
533
540
|
}
|
|
534
541
|
if (ctx.buildPatterns) {
|
|
535
542
|
parts.push("### Build Patterns", "", ctx.buildPatterns, "");
|
|
@@ -1226,7 +1233,7 @@ REFERENCE DOCS
|
|
|
1226
1233
|
[Optional \u2014 paths to docs/ files with background context. Omit if not needed.]
|
|
1227
1234
|
|
|
1228
1235
|
FILES LIKELY TOUCHED
|
|
1229
|
-
[files]
|
|
1236
|
+
[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
1237
|
|
|
1231
1238
|
EFFORT
|
|
1232
1239
|
[XS/S/M/L/XL]`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@papi-ai/server",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.58",
|
|
4
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",
|