@papi-ai/server 0.7.80 → 0.7.81
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 +107 -1
- package/dist/index.js +875 -57
- package/dist/prompts.js +36 -6
- package/package.json +1 -1
|
@@ -28,6 +28,7 @@ __export(git_exports, {
|
|
|
28
28
|
ensureTagAtHead: () => ensureTagAtHead,
|
|
29
29
|
findTaskCommitsOnBase: () => findTaskCommitsOnBase,
|
|
30
30
|
getBranchDiff: () => getBranchDiff,
|
|
31
|
+
getCommitFiles: () => getCommitFiles,
|
|
31
32
|
getCommitsSinceTag: () => getCommitsSinceTag,
|
|
32
33
|
getCurrentBranch: () => getCurrentBranch,
|
|
33
34
|
getDocPathsTouchedOnBranch: () => getDocPathsTouchedOnBranch,
|
|
@@ -41,11 +42,13 @@ __export(git_exports, {
|
|
|
41
42
|
getModifiedFiles: () => getModifiedFiles,
|
|
42
43
|
getOriginRepoSlug: () => getOriginRepoSlug,
|
|
43
44
|
getOriginUrl: () => getOriginUrl,
|
|
45
|
+
getPathsDifferingFrom: () => getPathsDifferingFrom,
|
|
44
46
|
getPullRequestUrl: () => getPullRequestUrl,
|
|
45
47
|
getRemoteBranchFiles: () => getRemoteBranchFiles,
|
|
46
48
|
getRootCommitHash: () => getRootCommitHash,
|
|
47
49
|
getStagedFiles: () => getStagedFiles,
|
|
48
50
|
getTagTarget: () => getTagTarget,
|
|
51
|
+
getTaskDiff: () => getTaskDiff,
|
|
49
52
|
getTaskIdsOnBranch: () => getTaskIdsOnBranch,
|
|
50
53
|
getTrackedModifiedFiles: () => getTrackedModifiedFiles,
|
|
51
54
|
getUnmergedBranches: () => getUnmergedBranches,
|
|
@@ -271,6 +274,50 @@ function getBranchDiff(cwd, base = "origin/main", maxBytes = 2e5) {
|
|
|
271
274
|
}
|
|
272
275
|
return "";
|
|
273
276
|
}
|
|
277
|
+
function getTaskDiff(cwd, taskId, base = "origin/main", maxBytes = 2e5) {
|
|
278
|
+
const truncate = (out) => out.length > maxBytes ? `${out.slice(0, maxBytes)}
|
|
279
|
+
|
|
280
|
+
... [diff truncated at ${Math.round(maxBytes / 1024)} KB]` : out;
|
|
281
|
+
try {
|
|
282
|
+
const shas = execFileSync(
|
|
283
|
+
"git",
|
|
284
|
+
["log", "--all", "--format=%H", `--grep=${taskId})`, "--fixed-strings"],
|
|
285
|
+
{ cwd, encoding: "utf-8", maxBuffer: 8 * 1024 * 1024 }
|
|
286
|
+
).split("\n").map((s) => s.trim()).filter(Boolean);
|
|
287
|
+
if (shas.length > 0) {
|
|
288
|
+
const parts = [];
|
|
289
|
+
for (const sha of [...shas].reverse()) {
|
|
290
|
+
try {
|
|
291
|
+
const one = execFileSync("git", ["diff", `${sha}^..${sha}`], {
|
|
292
|
+
cwd,
|
|
293
|
+
encoding: "utf-8",
|
|
294
|
+
maxBuffer: 32 * 1024 * 1024
|
|
295
|
+
});
|
|
296
|
+
if (one) parts.push(one);
|
|
297
|
+
} catch {
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
const out = parts.join("\n");
|
|
301
|
+
if (out) {
|
|
302
|
+
const range = shas.length === 1 ? shas[0].slice(0, 8) : `${shas[shas.length - 1].slice(0, 8)}\u2026${shas[0].slice(0, 8)}`;
|
|
303
|
+
return {
|
|
304
|
+
diff: truncate(out),
|
|
305
|
+
scope: "task-commits",
|
|
306
|
+
detail: `${shas.length} commit(s) for ${taskId} (${range}), each against its own parent`
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
} catch {
|
|
311
|
+
}
|
|
312
|
+
const branch = getCurrentBranch(cwd);
|
|
313
|
+
const diff = getBranchDiff(cwd, base, maxBytes);
|
|
314
|
+
if (!diff) return { diff: "", scope: "none", detail: "no diff resolved" };
|
|
315
|
+
return {
|
|
316
|
+
diff,
|
|
317
|
+
scope: "whole-branch",
|
|
318
|
+
detail: `no commit naming ${taskId} was found, so this is the ENTIRE diff of ${branch ?? "the current branch"} vs ${base} \u2014 it may include other tasks' work, and may not include this task's`
|
|
319
|
+
};
|
|
320
|
+
}
|
|
274
321
|
function getHeadCommitSubject(cwd) {
|
|
275
322
|
try {
|
|
276
323
|
const out = execFileSync("git", ["log", "-1", "--format=%s"], {
|
|
@@ -318,6 +365,28 @@ function branchExists(cwd, branch) {
|
|
|
318
365
|
return false;
|
|
319
366
|
}
|
|
320
367
|
}
|
|
368
|
+
function getPathsDifferingFrom(cwd, target) {
|
|
369
|
+
try {
|
|
370
|
+
const out = execFileSync("git", ["diff", "--name-only", "HEAD", target], {
|
|
371
|
+
cwd,
|
|
372
|
+
encoding: "utf-8"
|
|
373
|
+
});
|
|
374
|
+
return out.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
375
|
+
} catch {
|
|
376
|
+
return null;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
function getCommitFiles(cwd, ref = "HEAD") {
|
|
380
|
+
try {
|
|
381
|
+
const out = execFileSync("git", ["show", "--name-only", "--pretty=format:", ref], {
|
|
382
|
+
cwd,
|
|
383
|
+
encoding: "utf-8"
|
|
384
|
+
});
|
|
385
|
+
return out.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
386
|
+
} catch {
|
|
387
|
+
return null;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
321
390
|
function checkoutBranch(cwd, branch) {
|
|
322
391
|
try {
|
|
323
392
|
execFileSync("git", ["checkout", branch], { cwd, encoding: "utf-8" });
|
|
@@ -1272,7 +1341,7 @@ var init_proxy_adapter = __esm({
|
|
|
1272
1341
|
"listContributorReleasePrs",
|
|
1273
1342
|
"claimReview",
|
|
1274
1343
|
"getSiblingAds",
|
|
1275
|
-
"getSiblingRepoTasks"
|
|
1344
|
+
"getSiblingRepoTasks",
|
|
1276
1345
|
// task-2828 (C339): attributed-intelligence analytics reader — pg-only that cycle.
|
|
1277
1346
|
// task-2864 (C343): WIRED. getModelOutcomeStats now has an edge case handler (raw
|
|
1278
1347
|
// SQL via postgres.js mirroring the pg query + inlined computeModelOutcomes bucketing)
|
|
@@ -1296,6 +1365,28 @@ var init_proxy_adapter = __esm({
|
|
|
1296
1365
|
// (case handler + ALLOWED_METHODS/WRITE_METHODS entries), so it forwards for
|
|
1297
1366
|
// hosted callers and persists a project-scoped cycle_progress_steps row. Removed
|
|
1298
1367
|
// from NO_FORWARD (was the task-2484 pg-only gap) — hosted parity restored.
|
|
1368
|
+
//
|
|
1369
|
+
// (3) pg-only optimisations probed STRUCTURALLY with a local fallback beside them.
|
|
1370
|
+
// These are the dangerous class: the caller asks `typeof adapter.X === 'function'`
|
|
1371
|
+
// to decide whether the fast path exists, and the get-trap answers "yes" for any
|
|
1372
|
+
// name absent from this set. The probe then passes, the call forwards, and the
|
|
1373
|
+
// edge 403s — while a working fallback sits a few lines below, unreachable.
|
|
1374
|
+
// A method belongs here when BOTH are true: it is probed by `typeof` rather than
|
|
1375
|
+
// called unconditionally, and the probe's else-branch is a real fallback.
|
|
1376
|
+
//
|
|
1377
|
+
// task-3290 (C361): allocateActiveDecision + applyActiveDecisionUpdates are pg-only
|
|
1378
|
+
// (atomic id allocation; transactional batch apply). Both are probed in
|
|
1379
|
+
// services/strategy.ts — asDecisionIdAllocator and asDecisionBatchApplier — and both
|
|
1380
|
+
// have read-then-write / sequential fallbacks. Hosted users hit a 403 minting ANY
|
|
1381
|
+
// Active Decision via setup's AD seed or strategy_change until these were listed.
|
|
1382
|
+
"allocateActiveDecision",
|
|
1383
|
+
"applyActiveDecisionUpdates",
|
|
1384
|
+
// task-3290 (C361), same sweep: getLastZoomOutCycle was documented in the parity
|
|
1385
|
+
// ledger as "proxy NO_FORWARD → safe no-op" while NOT being in this set. It is
|
|
1386
|
+
// optional-chain probed in services/health.ts and wrapped in try/catch, so it
|
|
1387
|
+
// degraded rather than crashed — but every hosted `orient` paid a round-trip to
|
|
1388
|
+
// earn a silent 403. Listing it makes the ledger's claim true and skips the trip.
|
|
1389
|
+
"getLastZoomOutCycle"
|
|
1299
1390
|
]);
|
|
1300
1391
|
ProxyPapiAdapter = class _ProxyPapiAdapter {
|
|
1301
1392
|
endpoint;
|
|
@@ -1827,6 +1918,21 @@ Check PAPI_PROJECT_ID in your .mcp.json config. Find your project ID in the PAPI
|
|
|
1827
1918
|
updateDogfoodEntryStatus(id, status, linkedTaskId) {
|
|
1828
1919
|
return this.invoke("updateDogfoodEntryStatus", [id, status, linkedTaskId]);
|
|
1829
1920
|
}
|
|
1921
|
+
// --- Project conventions (task-3271) ---
|
|
1922
|
+
//
|
|
1923
|
+
// Wired to the edge handler from the start rather than parked in NO_FORWARD.
|
|
1924
|
+
// The hosted remote connector is the only install path an external user has,
|
|
1925
|
+
// so a local-only conventions store would be a feature nobody in the actual
|
|
1926
|
+
// user base can reach.
|
|
1927
|
+
listConventions() {
|
|
1928
|
+
return this.invoke("listConventions");
|
|
1929
|
+
}
|
|
1930
|
+
createConvention(convention) {
|
|
1931
|
+
return this.invoke("createConvention", [convention]);
|
|
1932
|
+
}
|
|
1933
|
+
deleteConvention(id) {
|
|
1934
|
+
return this.invoke("deleteConvention", [id]);
|
|
1935
|
+
}
|
|
1830
1936
|
// --- Harness inventory (task-1896) ---
|
|
1831
1937
|
getHarnessInventory() {
|
|
1832
1938
|
return this.invoke("getHarnessInventory");
|