@papi-ai/server 0.7.106 → 0.7.108
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 +13 -1
- package/dist/index.js +146 -47
- package/package.json +1 -1
|
@@ -12,6 +12,10 @@ var __export = (target, all) => {
|
|
|
12
12
|
function isSelfHostedDeployment(value) {
|
|
13
13
|
return value === "1" || value?.toLowerCase() === "true";
|
|
14
14
|
}
|
|
15
|
+
function isFossilSupabaseReference(value) {
|
|
16
|
+
if (!value) return false;
|
|
17
|
+
return value.includes(".pooler.supabase.com") || value.includes(DECOMMISSIONED_SUPABASE_PROJECT_REF);
|
|
18
|
+
}
|
|
15
19
|
function optionalBoolean(value, fallback) {
|
|
16
20
|
if (value == null || value.trim() === "") return fallback;
|
|
17
21
|
return isSelfHostedDeployment(value);
|
|
@@ -94,10 +98,11 @@ function calculateCycleMetrics(reports, currentCycle, window = 5) {
|
|
|
94
98
|
}
|
|
95
99
|
return { accuracy, velocity, unparsedEffortCount };
|
|
96
100
|
}
|
|
97
|
-
var CAPABILITY_REGISTRY, CAPABILITY_KEYS, HOSTED_APP_URL, HOSTED_MCP_URL, HOSTED_SUPABASE_URL, WAB_WINDOW_DAYS, WAB_WEEK_MS, EFFORT_SCALE;
|
|
101
|
+
var DECOMMISSIONED_SUPABASE_PROJECT_REF, CAPABILITY_REGISTRY, CAPABILITY_KEYS, HOSTED_APP_URL, HOSTED_MCP_URL, HOSTED_SUPABASE_URL, WAB_WINDOW_DAYS, WAB_WEEK_MS, EFFORT_SCALE;
|
|
98
102
|
var init_dist = __esm({
|
|
99
103
|
"../shared/dist/index.js"() {
|
|
100
104
|
"use strict";
|
|
105
|
+
DECOMMISSIONED_SUPABASE_PROJECT_REF = "guewgygcpcmrcoppihzx";
|
|
101
106
|
CAPABILITY_REGISTRY = [
|
|
102
107
|
// task-3384: the PLAN step. The landing page has advertised these three since
|
|
103
108
|
// the v5 control beat (components/marketing/landing/ControlC.tsx) with a code
|
|
@@ -2854,6 +2859,11 @@ var PLACEHOLDER_PATTERNS = [
|
|
|
2854
2859
|
];
|
|
2855
2860
|
function validateDatabaseUrl(connectionString) {
|
|
2856
2861
|
const lower = connectionString.toLowerCase().trim();
|
|
2862
|
+
if (isFossilSupabaseReference(connectionString)) {
|
|
2863
|
+
throw new Error(
|
|
2864
|
+
"This config points at PAPI's old hosted database, which was migrated.\nRegenerate your config at https://getpapi.ai \u2014 your projects and data are intact."
|
|
2865
|
+
);
|
|
2866
|
+
}
|
|
2857
2867
|
if (PLACEHOLDER_PATTERNS.some((p) => lower.includes(p.toLowerCase()))) {
|
|
2858
2868
|
throw new Error(
|
|
2859
2869
|
"DATABASE_URL contains a placeholder value and is not configured.\nReplace it with your actual Supabase connection string in .mcp.json.\nIf you don't have one yet, contact the PAPI admin for access."
|
|
@@ -2868,10 +2878,12 @@ Check your .mcp.json configuration.`
|
|
|
2868
2878
|
}
|
|
2869
2879
|
}
|
|
2870
2880
|
var _connectionStatus = "offline";
|
|
2881
|
+
var _lastAdapterType = null;
|
|
2871
2882
|
var _pathIdentityChecked = false;
|
|
2872
2883
|
async function createAdapter(optionsOrType, maybePapiDir) {
|
|
2873
2884
|
const options = typeof optionsOrType === "string" ? { adapterType: optionsOrType, papiDir: maybePapiDir } : optionsOrType;
|
|
2874
2885
|
const { adapterType, papiDir, papiEndpoint } = options;
|
|
2886
|
+
_lastAdapterType = adapterType;
|
|
2875
2887
|
switch (adapterType) {
|
|
2876
2888
|
case "pg": {
|
|
2877
2889
|
const { PgAdapter, PgPapiAdapter, configFromEnv } = await import("@papi-ai/adapter-pg");
|
package/dist/index.js
CHANGED
|
@@ -14,6 +14,10 @@ import { randomUUID } from "crypto";
|
|
|
14
14
|
function isSelfHostedDeployment(value) {
|
|
15
15
|
return value === "1" || value?.toLowerCase() === "true";
|
|
16
16
|
}
|
|
17
|
+
function isFossilSupabaseReference(value) {
|
|
18
|
+
if (!value) return false;
|
|
19
|
+
return value.includes(".pooler.supabase.com") || value.includes(DECOMMISSIONED_SUPABASE_PROJECT_REF);
|
|
20
|
+
}
|
|
17
21
|
function isCapabilityEnabled(caps, key) {
|
|
18
22
|
const stored = caps?.[key];
|
|
19
23
|
if (stored != null) return stored !== false;
|
|
@@ -788,10 +792,11 @@ function parsePhaseBlock(block) {
|
|
|
788
792
|
if (isNaN(order)) return null;
|
|
789
793
|
return { id, slug, label, description, status, order };
|
|
790
794
|
}
|
|
791
|
-
var CAPABILITY_REGISTRY, CAPABILITY_KEYS, ASSIGNABLE_CONTRIBUTOR_ROLES, SENSITIVE_CHANGELOG_PATTERNS, CONTRIBUTOR_PRICING_URL, PROPOSAL_EVENT_TYPES, HOSTED_APP_URL, HOSTED_MCP_URL, HOSTED_SUPABASE_URL, SEVERITY_ORDER, NONE_RE, AD_HOC_PLACEHOLDER_RE, NONE_LEAD_RE, CONTRAST_LEAD_RE, MIN_REASON_LENGTH, LOW_SEVERITIES, WAB_WINDOW_DAYS, WAB_DEFAULT_WEEKS, WAB_WEEK_MS, PRODUCT_MARKER, MECHANICS_MARKER, CHECK_VALUE_MAX, VALID_EFFORT_SIZES, SECTION_HEADERS, VALID_EFFORT_SIZES2, EFFORT_SCALE, NONE_PATTERN, NONE_PATTERN2, VALID_STATUSES, PHASES_START, PHASES_END;
|
|
795
|
+
var DECOMMISSIONED_SUPABASE_PROJECT_REF, CAPABILITY_REGISTRY, CAPABILITY_KEYS, ASSIGNABLE_CONTRIBUTOR_ROLES, SENSITIVE_CHANGELOG_PATTERNS, CONTRIBUTOR_PRICING_URL, PROPOSAL_EVENT_TYPES, HOSTED_APP_URL, HOSTED_MCP_URL, HOSTED_SUPABASE_URL, SEVERITY_ORDER, NONE_RE, AD_HOC_PLACEHOLDER_RE, NONE_LEAD_RE, CONTRAST_LEAD_RE, MIN_REASON_LENGTH, LOW_SEVERITIES, WAB_WINDOW_DAYS, WAB_DEFAULT_WEEKS, WAB_WEEK_MS, PRODUCT_MARKER, MECHANICS_MARKER, CHECK_VALUE_MAX, VALID_EFFORT_SIZES, SECTION_HEADERS, VALID_EFFORT_SIZES2, EFFORT_SCALE, NONE_PATTERN, NONE_PATTERN2, VALID_STATUSES, PHASES_START, PHASES_END;
|
|
792
796
|
var init_dist = __esm({
|
|
793
797
|
"../shared/dist/index.js"() {
|
|
794
798
|
"use strict";
|
|
799
|
+
DECOMMISSIONED_SUPABASE_PROJECT_REF = "guewgygcpcmrcoppihzx";
|
|
795
800
|
CAPABILITY_REGISTRY = [
|
|
796
801
|
// task-3384: the PLAN step. The landing page has advertised these three since
|
|
797
802
|
// the v5 control beat (components/marketing/landing/ControlC.tsx) with a code
|
|
@@ -7175,6 +7180,11 @@ var PLACEHOLDER_PATTERNS = [
|
|
|
7175
7180
|
];
|
|
7176
7181
|
function validateDatabaseUrl(connectionString) {
|
|
7177
7182
|
const lower = connectionString.toLowerCase().trim();
|
|
7183
|
+
if (isFossilSupabaseReference(connectionString)) {
|
|
7184
|
+
throw new Error(
|
|
7185
|
+
"This config points at PAPI's old hosted database, which was migrated.\nRegenerate your config at https://getpapi.ai \u2014 your projects and data are intact."
|
|
7186
|
+
);
|
|
7187
|
+
}
|
|
7178
7188
|
if (PLACEHOLDER_PATTERNS.some((p) => lower.includes(p.toLowerCase()))) {
|
|
7179
7189
|
throw new Error(
|
|
7180
7190
|
"DATABASE_URL contains a placeholder value and is not configured.\nReplace it with your actual Supabase connection string in .mcp.json.\nIf you don't have one yet, contact the PAPI admin for access."
|
|
@@ -7189,6 +7199,10 @@ Check your .mcp.json configuration.`
|
|
|
7189
7199
|
}
|
|
7190
7200
|
}
|
|
7191
7201
|
var _connectionStatus = "offline";
|
|
7202
|
+
var _lastAdapterType = null;
|
|
7203
|
+
function getLastAdapterType() {
|
|
7204
|
+
return _lastAdapterType;
|
|
7205
|
+
}
|
|
7192
7206
|
var _pathIdentityChecked = false;
|
|
7193
7207
|
function getConnectionStatus() {
|
|
7194
7208
|
return _connectionStatus;
|
|
@@ -7196,6 +7210,7 @@ function getConnectionStatus() {
|
|
|
7196
7210
|
async function createAdapter(optionsOrType, maybePapiDir) {
|
|
7197
7211
|
const options = typeof optionsOrType === "string" ? { adapterType: optionsOrType, papiDir: maybePapiDir } : optionsOrType;
|
|
7198
7212
|
const { adapterType, papiDir, papiEndpoint } = options;
|
|
7213
|
+
_lastAdapterType = adapterType;
|
|
7199
7214
|
switch (adapterType) {
|
|
7200
7215
|
case "pg": {
|
|
7201
7216
|
const { PgAdapter, PgPapiAdapter, configFromEnv } = await import("@papi-ai/adapter-pg");
|
|
@@ -12410,6 +12425,19 @@ ${cleanContent}`;
|
|
|
12410
12425
|
`task-3670 self-heal: ${repairedCycles.length} task(s) had lost cycle membership and were re-assigned (${repairedCycles.join(", ")})`
|
|
12411
12426
|
);
|
|
12412
12427
|
}
|
|
12428
|
+
let health;
|
|
12429
|
+
try {
|
|
12430
|
+
health = await adapter2.getCycleHealth?.();
|
|
12431
|
+
} catch (err) {
|
|
12432
|
+
verifyWarnings.push(
|
|
12433
|
+
`task-3733: could not re-verify the cycle row after write (${err instanceof Error ? err.message : String(err)}) \u2014 cycle membership was written and repaired, but this final check could not confirm it.`
|
|
12434
|
+
);
|
|
12435
|
+
}
|
|
12436
|
+
if (health && health.totalCycles !== newCycleNumber) {
|
|
12437
|
+
throw new Error(
|
|
12438
|
+
`Plan apply committed, but the cycle row for Cycle ${newCycleNumber} did not take: getCycleHealth() reports the caller's current cycle as ${health.totalCycles}. Task assignments were written and repaired, but the cycle entity itself is stale \u2014 investigate the planWriteBack cycle upsert before trusting this apply.`
|
|
12439
|
+
);
|
|
12440
|
+
}
|
|
12413
12441
|
const allWarnings = [...result.warnings, ...verifyWarnings, ...earlyCreateWarnings];
|
|
12414
12442
|
const handoffCount = data.cycleHandoffs?.length ?? 0;
|
|
12415
12443
|
const correctionCount = data.boardCorrections?.length ?? 0;
|
|
@@ -22097,60 +22125,87 @@ Releasing to a non-base branch (e.g. dev) is unaffected.` + resolutionNote
|
|
|
22097
22125
|
}
|
|
22098
22126
|
const releaseRole = callerRole === "release_manager" ? "release manager" : "editor";
|
|
22099
22127
|
tracker.mark("contributor-pr-reconciliation");
|
|
22128
|
+
const closeContributorCycle = (cycleOverride) => closeCycleState(
|
|
22129
|
+
config2,
|
|
22130
|
+
adapter2,
|
|
22131
|
+
version,
|
|
22132
|
+
cycleOverride ?? cycleToClose ?? void 0,
|
|
22133
|
+
{
|
|
22134
|
+
force: force ?? false,
|
|
22135
|
+
skipVersion: skipVersion ?? false,
|
|
22136
|
+
callerUserId: gate.callerUserId
|
|
22137
|
+
}
|
|
22138
|
+
);
|
|
22139
|
+
let reconciled = null;
|
|
22100
22140
|
try {
|
|
22101
|
-
|
|
22102
|
-
|
|
22103
|
-
|
|
22104
|
-
|
|
22105
|
-
|
|
22106
|
-
|
|
22107
|
-
|
|
22108
|
-
|
|
22109
|
-
|
|
22110
|
-
}
|
|
22111
|
-
|
|
22112
|
-
|
|
22113
|
-
|
|
22114
|
-
|
|
22115
|
-
|
|
22116
|
-
|
|
22117
|
-
|
|
22118
|
-
|
|
22119
|
-
|
|
22120
|
-
|
|
22141
|
+
reconciled = await reconcileContributorReleasePrs(config2, adapter2, gate.callerUserId, cycleToClose);
|
|
22142
|
+
} catch (err) {
|
|
22143
|
+
console.error(`[release] contributor PR reconciliation failed (non-blocking): ${err instanceof Error ? err.message : String(err)}`);
|
|
22144
|
+
}
|
|
22145
|
+
if (reconciled?.merged.length) {
|
|
22146
|
+
const latest = reconciled.merged[0];
|
|
22147
|
+
let caps2 = {};
|
|
22148
|
+
try {
|
|
22149
|
+
const info = adapter2.getProjectInfo ? await adapter2.getProjectInfo() : null;
|
|
22150
|
+
caps2 = info?.capabilities ?? {};
|
|
22151
|
+
} catch {
|
|
22152
|
+
caps2 = {};
|
|
22153
|
+
}
|
|
22154
|
+
let closed;
|
|
22155
|
+
try {
|
|
22156
|
+
closed = await closeContributorCycle(latest.cycle);
|
|
22157
|
+
} catch (err) {
|
|
22158
|
+
return errorResponse(err instanceof Error ? err.message : String(err));
|
|
22159
|
+
}
|
|
22160
|
+
await recordReadinessVerified(tracker);
|
|
22161
|
+
await recordQualityGate(tracker, evaluateReleaseGate(caps2, config2.gateCommand, gateResult), caps2);
|
|
22162
|
+
await completeRelease(tracker, {
|
|
22163
|
+
cycleClosed: closed.resolvedCycleNum > 0 ? closed.resolvedCycleNum : latest.cycle,
|
|
22164
|
+
version,
|
|
22165
|
+
caps: caps2,
|
|
22166
|
+
branchMerges: latest.branch ? [{ branch: latest.branch, prUrl: latest.prUrl }] : [],
|
|
22167
|
+
changelogEmitted: false
|
|
22168
|
+
});
|
|
22169
|
+
const localHandoff = isHostedTransport() ? `
|
|
22121
22170
|
${buildHostedGitDirective({
|
|
22122
|
-
|
|
22123
|
-
|
|
22124
|
-
|
|
22125
|
-
|
|
22126
|
-
|
|
22127
|
-
|
|
22128
|
-
|
|
22129
|
-
|
|
22130
|
-
|
|
22131
|
-
|
|
22171
|
+
version,
|
|
22172
|
+
branch,
|
|
22173
|
+
skipVersion: skipVersion ?? false,
|
|
22174
|
+
harnessCanBuild: detectHarness(clientName).build,
|
|
22175
|
+
harnessKnown: detectHarness(clientName).known,
|
|
22176
|
+
harnessLabel: detectHarness(clientName).label,
|
|
22177
|
+
changelogSection: null
|
|
22178
|
+
})}` : "";
|
|
22179
|
+
const cycleLabel = closed.resolvedCycleNum > 0 ? `Cycle ${closed.resolvedCycleNum}` : latest.cycle ? `Cycle ${latest.cycle}` : "The contributor cycle";
|
|
22180
|
+
return textResponse(
|
|
22181
|
+
`## Release ${version} \u2014 contributor PR merged
|
|
22132
22182
|
|
|
22133
22183
|
PAPI detected that ${latest.prUrl} was merged on GitHub and reconciled the contributor release. GitHub granted the merge permission; your PAPI **${releaseRole}** role granted the release workflow.
|
|
22134
22184
|
|
|
22135
|
-
${
|
|
22185
|
+
${cycleLabel} remains **complete**, and the release is now recorded as **released** in PAPI.` + localHandoff + `
|
|
22136
22186
|
|
|
22137
22187
|
Next: run \`plan\` to start your next cycle.`
|
|
22138
|
-
|
|
22188
|
+
);
|
|
22189
|
+
}
|
|
22190
|
+
if (reconciled?.open.length) {
|
|
22191
|
+
const openCycle = cycleToClose !== null ? reconciled.open.find((pr) => pr.cycle === cycleToClose)?.cycle ?? null : reconciled.open[0].cycle;
|
|
22192
|
+
if (openCycle !== null && openCycle !== void 0) {
|
|
22193
|
+
try {
|
|
22194
|
+
await closeContributorCycle(openCycle);
|
|
22195
|
+
} catch (err) {
|
|
22196
|
+
return errorResponse(err instanceof Error ? err.message : String(err));
|
|
22197
|
+
}
|
|
22139
22198
|
}
|
|
22140
|
-
|
|
22141
|
-
|
|
22142
|
-
|
|
22143
|
-
`## Release ${version} \u2014 contributor PR awaiting merge
|
|
22199
|
+
const prLines = reconciled.open.map((p) => `- ${p.prUrl}`).join("\n");
|
|
22200
|
+
return textResponse(
|
|
22201
|
+
`## Release ${version} \u2014 contributor PR awaiting merge
|
|
22144
22202
|
|
|
22145
22203
|
${prLines}
|
|
22146
22204
|
|
|
22147
22205
|
Your PAPI **${releaseRole}** role allowed this release PR. Merge permission is controlled separately by GitHub: if GitHub lets you merge, review and merge it there; otherwise a repository maintainer must merge it.
|
|
22148
22206
|
|
|
22149
22207
|
After it is merged, run \`release\` again so PAPI can detect the merge and finish the release record.`
|
|
22150
|
-
|
|
22151
|
-
}
|
|
22152
|
-
} catch (err) {
|
|
22153
|
-
console.error(`[release] contributor PR reconciliation failed (non-blocking): ${err instanceof Error ? err.message : String(err)}`);
|
|
22208
|
+
);
|
|
22154
22209
|
}
|
|
22155
22210
|
if (isHostedTransport()) {
|
|
22156
22211
|
return errorResponse(
|
|
@@ -23089,7 +23144,7 @@ function getUnresolvedDeps(task, allTasks) {
|
|
|
23089
23144
|
const taskStatusMap = new Map(allTasks.map((t) => [t.id, t.status]));
|
|
23090
23145
|
return deps.filter((depId) => {
|
|
23091
23146
|
const status = taskStatusMap.get(depId);
|
|
23092
|
-
return status !== "Done";
|
|
23147
|
+
return status !== "Done" && status !== "Cancelled" && status !== "Archived";
|
|
23093
23148
|
});
|
|
23094
23149
|
}
|
|
23095
23150
|
function resolveDepCycleBranch(cycleBranches, cycleNumber, upstreamModule, dependentModule) {
|
|
@@ -29912,6 +29967,30 @@ async function handleReviewClaim(adapter2, config2, args) {
|
|
|
29912
29967
|
import { randomUUID as randomUUID12 } from "crypto";
|
|
29913
29968
|
import { access as access2, readFile as readFile5, writeFile as writeFile3 } from "fs/promises";
|
|
29914
29969
|
import path6 from "path";
|
|
29970
|
+
init_dist();
|
|
29971
|
+
var FOSSIL_CONFIG_MESSAGE = [
|
|
29972
|
+
"This config points at PAPI's old hosted database, which was migrated.",
|
|
29973
|
+
"Regenerate your config at https://getpapi.ai \u2014 your projects and data are intact."
|
|
29974
|
+
].join("\n");
|
|
29975
|
+
function extractPapiOwnedConfigText(existingConfig, agent) {
|
|
29976
|
+
if (agent === "codex") {
|
|
29977
|
+
const match = existingConfig.match(/\[mcp_servers\.papi\][\s\S]*?(?=\n\[|$)/);
|
|
29978
|
+
return match ? match[0] : existingConfig;
|
|
29979
|
+
}
|
|
29980
|
+
if (agent === "hermes") {
|
|
29981
|
+
const match = existingConfig.match(/^[ \t]*papi[ \t]*:[\s\S]*?(?=\n[ \t]{0,2}\S[^\n]*:[ \t]*$|$)/m);
|
|
29982
|
+
return match ? match[0] : existingConfig;
|
|
29983
|
+
}
|
|
29984
|
+
try {
|
|
29985
|
+
const parsed = JSON.parse(existingConfig);
|
|
29986
|
+
const container = parsed.mcpServers ?? parsed.servers ?? parsed.mcp;
|
|
29987
|
+
const papiEntry = container?.papi;
|
|
29988
|
+
const env = papiEntry?.env ?? papiEntry?.environment;
|
|
29989
|
+
if (env) return JSON.stringify(env);
|
|
29990
|
+
} catch {
|
|
29991
|
+
}
|
|
29992
|
+
return existingConfig;
|
|
29993
|
+
}
|
|
29915
29994
|
var initTool = {
|
|
29916
29995
|
name: "init",
|
|
29917
29996
|
description: "Write the MCP config file that connects this project to PAPI. Generates .mcp.json, or the equivalent for whichever MCP client you use \u2014 Claude Code, Cursor, VS Code, Windsurf, OpenCode, Amazon Q, Kilo Code, Gemini CLI, Codex CLI, or Hermes Agent. Config-only \u2014 does not create any project data. Run this first, then run `setup` to create your PAPI project.",
|
|
@@ -30188,6 +30267,11 @@ async function handleInit(config2, args) {
|
|
|
30188
30267
|
await access2(mcpJsonPath);
|
|
30189
30268
|
existingConfig = await readFile5(mcpJsonPath, "utf-8");
|
|
30190
30269
|
} catch {
|
|
30270
|
+
}
|
|
30271
|
+
if (existingConfig && isFossilSupabaseReference(extractPapiOwnedConfigText(existingConfig, agent))) {
|
|
30272
|
+
return errorResponse(`${FOSSIL_CONFIG_MESSAGE}
|
|
30273
|
+
|
|
30274
|
+
Path: ${mcpJsonPath}`);
|
|
30191
30275
|
}
|
|
30192
30276
|
if (existingConfig && !force) {
|
|
30193
30277
|
const hasPapiServer = (() => {
|
|
@@ -30341,6 +30425,9 @@ ${writeNote}
|
|
|
30341
30425
|
` + formatFilesToWriteSection(collector)
|
|
30342
30426
|
);
|
|
30343
30427
|
}
|
|
30428
|
+
if (isDatabaseUser && isFossilSupabaseReference(process.env.DATABASE_URL)) {
|
|
30429
|
+
return errorResponse(FOSSIL_CONFIG_MESSAGE);
|
|
30430
|
+
}
|
|
30344
30431
|
if (isDatabaseUser) {
|
|
30345
30432
|
const projectId = randomUUID12();
|
|
30346
30433
|
const envVars = {
|
|
@@ -30379,7 +30466,7 @@ ${writeNote}
|
|
|
30379
30466
|
"",
|
|
30380
30467
|
"## Next Steps",
|
|
30381
30468
|
"",
|
|
30382
|
-
...process.env.DATABASE_URL ? ["1. **Restart your MCP client** to pick up the new config."] : [`1. **Set your DATABASE_URL** \u2014 replace \`<YOUR_DATABASE_URL>\` in \`${target.displayPath}\` with
|
|
30469
|
+
...process.env.DATABASE_URL ? ["1. **Restart your MCP client** to pick up the new config."] : [`1. **Set your DATABASE_URL** \u2014 replace \`<YOUR_DATABASE_URL>\` in \`${target.displayPath}\` with the connection string for the self-hosted Postgres/Auth stack you are running (production resolves this over the internal-only VPS tunnel \u2014 see \`infra/vps/self-host-runbook.md\`). This is not a managed Supabase pooler string.`],
|
|
30383
30470
|
...process.env.PAPI_USER_ID ? [] : ["2. **Set your PAPI_USER_ID** \u2014 replace `<YOUR_ACCOUNT_UUID>` with your account UUID (getpapi.ai \u2192 Settings \u2192 Account). Release and reviews use it to recognise you as the owner."],
|
|
30384
30471
|
`${process.env.PAPI_USER_ID ? "2" : "3"}. **Run \`setup\`** \u2014 this scaffolds your project with a Product Brief, Active Decisions, and CLAUDE.md.`
|
|
30385
30472
|
].join("\n");
|
|
@@ -30427,6 +30514,9 @@ function formatWorkspaceModeLine(result) {
|
|
|
30427
30514
|
}
|
|
30428
30515
|
|
|
30429
30516
|
// src/services/health.ts
|
|
30517
|
+
function formatDegradedConnectionLabel() {
|
|
30518
|
+
return getLastAdapterType() === "proxy" ? "connection degraded \u2014 data may be stale. Regenerate your config at https://getpapi.ai if this persists." : "connection degraded \u2014 data may be stale. Check DATABASE_URL in .mcp.json";
|
|
30519
|
+
}
|
|
30430
30520
|
function computeZoomOutWarning(cycleNumber, lastZoomOutCycle) {
|
|
30431
30521
|
if (cycleNumber <= 0) return "";
|
|
30432
30522
|
const baseline = lastZoomOutCycle > 0 ? lastZoomOutCycle : 1;
|
|
@@ -31534,7 +31624,7 @@ function formatOrientSummary(health, buildInfo, hierarchy, latestTag, projectRoo
|
|
|
31534
31624
|
lines.push("");
|
|
31535
31625
|
if (health.connectionStatus !== "offline") {
|
|
31536
31626
|
const statusIcon = health.connectionStatus === "connected" ? "\u2713" : "\u26A0\uFE0F";
|
|
31537
|
-
const statusLabel = health.connectionStatus === "connected" ? "
|
|
31627
|
+
const statusLabel = health.connectionStatus === "connected" ? "connected" : formatDegradedConnectionLabel();
|
|
31538
31628
|
lines.push(`**Connection:** ${statusIcon} ${statusLabel}`);
|
|
31539
31629
|
lines.push("");
|
|
31540
31630
|
}
|
|
@@ -36326,8 +36416,11 @@ function startHttpTransport(opts) {
|
|
|
36326
36416
|
const installClient = typeof clientHeader === "string" && KNOWN_INSTALL_CLIENTS.has(clientHeader) ? clientHeader : "direct";
|
|
36327
36417
|
const projectIdHeader = req.headers["x-papi-project-id"];
|
|
36328
36418
|
const projectId = typeof projectIdHeader === "string" && projectIdHeader.length > 0 ? projectIdHeader : void 0;
|
|
36329
|
-
if (req.method !== "POST"
|
|
36330
|
-
sendError(res, {
|
|
36419
|
+
if (req.method !== "POST") {
|
|
36420
|
+
sendError(res, {
|
|
36421
|
+
status: 405,
|
|
36422
|
+
body: { error: "method_not_allowed", reason: "server does not support server-initiated SSE; use POST" }
|
|
36423
|
+
});
|
|
36331
36424
|
return;
|
|
36332
36425
|
}
|
|
36333
36426
|
const chunks = [];
|
|
@@ -36608,6 +36701,12 @@ async function dispatchRequest(args) {
|
|
|
36608
36701
|
}
|
|
36609
36702
|
}
|
|
36610
36703
|
|
|
36704
|
+
// src/lib/version-check.ts
|
|
36705
|
+
init_dist();
|
|
36706
|
+
function shouldCheckForUpdate(version, selfHostFlag) {
|
|
36707
|
+
return version !== "unknown" && !isSelfHostedDeployment(selfHostFlag);
|
|
36708
|
+
}
|
|
36709
|
+
|
|
36611
36710
|
// src/index.ts
|
|
36612
36711
|
init_dist();
|
|
36613
36712
|
var __dirname = dirname7(fileURLToPath5(import.meta.url));
|
|
@@ -36752,7 +36851,7 @@ If you already have an account, check that both **PAPI_PROJECT_ID** and **PAPI_D
|
|
|
36752
36851
|
}));
|
|
36753
36852
|
}
|
|
36754
36853
|
}
|
|
36755
|
-
if (pkgVersion
|
|
36854
|
+
if (shouldCheckForUpdate(pkgVersion, process.env["PAPI_SELF_HOST"])) {
|
|
36756
36855
|
(async () => {
|
|
36757
36856
|
try {
|
|
36758
36857
|
const controller = new AbortController();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@papi-ai/server",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.108",
|
|
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",
|