@papi-ai/server 0.7.60 → 0.7.61
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 +6 -1
- package/dist/index.js +166 -17
- package/package.json +1 -1
|
@@ -1189,7 +1189,12 @@ var init_proxy_adapter = __esm({
|
|
|
1189
1189
|
"listContributorReleasePrs",
|
|
1190
1190
|
"claimReview",
|
|
1191
1191
|
"getSiblingAds",
|
|
1192
|
-
"getSiblingRepoTasks"
|
|
1192
|
+
"getSiblingRepoTasks",
|
|
1193
|
+
// task-2828 (C339): attributed-intelligence analytics reader — pg-only this cycle.
|
|
1194
|
+
// Hosted forwarding needs a SECURITY DEFINER RPC + edge handler (like task-2394 did
|
|
1195
|
+
// for getModuleEstimationStats); until then keep it here so hosted degrades to a
|
|
1196
|
+
// safe `undefined` rather than forwarding into a 403. Wire under task-2390.
|
|
1197
|
+
"getModelOutcomeStats"
|
|
1193
1198
|
// task-2394 (C329) — Batch A wired: findPendingDocActionsForTask,
|
|
1194
1199
|
// getModuleEstimationStats and getDecisionScorePatterns now have edge case handlers
|
|
1195
1200
|
// (each backed by a SECURITY DEFINER RPC, migration 20260714140000) plus
|
package/dist/index.js
CHANGED
|
@@ -1306,7 +1306,12 @@ var init_proxy_adapter = __esm({
|
|
|
1306
1306
|
"listContributorReleasePrs",
|
|
1307
1307
|
"claimReview",
|
|
1308
1308
|
"getSiblingAds",
|
|
1309
|
-
"getSiblingRepoTasks"
|
|
1309
|
+
"getSiblingRepoTasks",
|
|
1310
|
+
// task-2828 (C339): attributed-intelligence analytics reader — pg-only this cycle.
|
|
1311
|
+
// Hosted forwarding needs a SECURITY DEFINER RPC + edge handler (like task-2394 did
|
|
1312
|
+
// for getModuleEstimationStats); until then keep it here so hosted degrades to a
|
|
1313
|
+
// safe `undefined` rather than forwarding into a 403. Wire under task-2390.
|
|
1314
|
+
"getModelOutcomeStats"
|
|
1310
1315
|
// task-2394 (C329) — Batch A wired: findPendingDocActionsForTask,
|
|
1311
1316
|
// getModuleEstimationStats and getDecisionScorePatterns now have edge case handlers
|
|
1312
1317
|
// (each backed by a SECURITY DEFINER RPC, migration 20260714140000) plus
|
|
@@ -10946,7 +10951,7 @@ function computeCarryForwardStaleness(log2, doneTaskIds) {
|
|
|
10946
10951
|
if (stale.length === 0) return void 0;
|
|
10947
10952
|
const lines = stale.map(([id, count]) => `- **${id}** \u2014 deferred ${count} consecutive cycle(s)`);
|
|
10948
10953
|
return [
|
|
10949
|
-
`\u26A0\uFE0F ${stale.length} task(s) have been in carry-forward for 3+ consecutive cycles. The planner must resolve each \u2014 either escalate to P1 High or
|
|
10954
|
+
`\u26A0\uFE0F ${stale.length} task(s) have been in carry-forward for 3+ consecutive cycles. The planner must resolve each \u2014 either escalate it to P1 High, or move it to Deferred with a reason. Do NOT cancel a stale carry-forward task: cancelling removes it from the owner's field of view, and only the owner may cancel. Deferring again without a fresh justification is not acceptable.`,
|
|
10950
10955
|
"",
|
|
10951
10956
|
...lines
|
|
10952
10957
|
].join("\n");
|
|
@@ -11096,6 +11101,15 @@ async function resolveOwnerGate(adapter2, config2) {
|
|
|
11096
11101
|
|
|
11097
11102
|
// src/services/plan.ts
|
|
11098
11103
|
var PLAN_BUILD_REPORT_BUDGET = { maxReports: 12, fieldBudget: 280 };
|
|
11104
|
+
function leadChainWithRecommended(chain, recommendedTaskId) {
|
|
11105
|
+
const rec = recommendedTaskId?.trim();
|
|
11106
|
+
const existing = (chain ?? "").trim();
|
|
11107
|
+
if (!rec) return existing || void 0;
|
|
11108
|
+
const firstMentioned = existing.match(/task-\d+/)?.[0];
|
|
11109
|
+
if (firstMentioned === rec) return existing || void 0;
|
|
11110
|
+
const lead = `Build order: ${rec} first.`;
|
|
11111
|
+
return existing ? `${lead} ${existing}` : lead;
|
|
11112
|
+
}
|
|
11099
11113
|
async function resolvePlanScope(adapter2, config2) {
|
|
11100
11114
|
const gate = await resolveOwnerGate(adapter2, config2);
|
|
11101
11115
|
return { callerUserId: gate.callerUserId, ownerUserId: gate.ownerUserId, callerIsOwner: gate.callerIsOwner };
|
|
@@ -12044,7 +12058,12 @@ ${cleanContent}`;
|
|
|
12044
12058
|
// project owner when unset, so owner-operated plans stay correct).
|
|
12045
12059
|
...options.ownerUserId ? { userId: options.ownerUserId } : {},
|
|
12046
12060
|
// task-2483 (C319): persist the plan's Dependency Chain build-order markdown.
|
|
12047
|
-
|
|
12061
|
+
// task-2823 (C338): seed it to lead with recommendedTaskId when the plan omits a
|
|
12062
|
+
// chain or it doesn't lead with the planner's pick, so the hub next-move agrees.
|
|
12063
|
+
...(() => {
|
|
12064
|
+
const chain = leadChainWithRecommended(data.dependencyChain, data.recommendedTaskId);
|
|
12065
|
+
return chain ? { dependencyChain: chain } : {};
|
|
12066
|
+
})()
|
|
12048
12067
|
};
|
|
12049
12068
|
const earlyCreateWarnings = [];
|
|
12050
12069
|
try {
|
|
@@ -12477,7 +12496,13 @@ ${cleanContent}`;
|
|
|
12477
12496
|
...options.ownerUserId ? { userId: options.ownerUserId } : {},
|
|
12478
12497
|
// task-2483 (C319): persist the plan's Dependency Chain build-order markdown.
|
|
12479
12498
|
// This full write patches the early minimal row created in Phase 1.
|
|
12480
|
-
|
|
12499
|
+
// task-2823 (C338): seed it to lead with recommendedTaskId (mapped from any
|
|
12500
|
+
// new-task tempId) so the hub next-move matches the planner's explicit pick.
|
|
12501
|
+
...(() => {
|
|
12502
|
+
const recId = data.recommendedTaskId ? newTaskIdMap.get(data.recommendedTaskId) ?? data.recommendedTaskId : null;
|
|
12503
|
+
const chain = leadChainWithRecommended(data.dependencyChain, recId);
|
|
12504
|
+
return chain ? { dependencyChain: chain } : {};
|
|
12505
|
+
})()
|
|
12481
12506
|
};
|
|
12482
12507
|
await adapter2.createCycle(cycle);
|
|
12483
12508
|
} catch (err) {
|
|
@@ -13053,7 +13078,6 @@ function defaultHint(tool) {
|
|
|
13053
13078
|
function buildSubagentDispatchPrompt(input) {
|
|
13054
13079
|
const {
|
|
13055
13080
|
tool,
|
|
13056
|
-
applyMode,
|
|
13057
13081
|
cycleNumber = 0,
|
|
13058
13082
|
strategyReviewWarning = "",
|
|
13059
13083
|
taskId,
|
|
@@ -13065,7 +13089,7 @@ function buildSubagentDispatchPrompt(input) {
|
|
|
13065
13089
|
const isReview = tool === "review_submit";
|
|
13066
13090
|
let applyNote;
|
|
13067
13091
|
if (tool === "plan") {
|
|
13068
|
-
applyNote = `\`plan\` again with mode="apply", llm_response=<sub-agent output>,
|
|
13092
|
+
applyNote = `\`plan\` again with mode="apply", llm_response=<sub-agent output>, cycle_number=${cycleNumber + 1}, strategy_review_warning=${JSON.stringify(strategyReviewWarning)}`;
|
|
13069
13093
|
} else if (tool === "strategy_review") {
|
|
13070
13094
|
applyNote = `\`strategy_review\` again with mode="apply", llm_response=<sub-agent output>, cycle_number=${cycleNumber}`;
|
|
13071
13095
|
} else if (tool === "zoom_out") {
|
|
@@ -13129,6 +13153,105 @@ Do NOT post-process the sub-agent reply. The apply path expects the full structu
|
|
|
13129
13153
|
step2Note
|
|
13130
13154
|
].join("\n");
|
|
13131
13155
|
}
|
|
13156
|
+
var REVIEW_PRESETS = {
|
|
13157
|
+
// Minimal gate: does it work, and is every write actually read (AD-74)?
|
|
13158
|
+
gate: ["correctness", "wiring"],
|
|
13159
|
+
// Everything.
|
|
13160
|
+
full: ["correctness", "security", "wiring", "test-quality", "scope-drift"],
|
|
13161
|
+
// Security first, plus correctness and a lighter wiring check.
|
|
13162
|
+
"security-focused": ["security", "correctness", "wiring"]
|
|
13163
|
+
};
|
|
13164
|
+
var LENS_INSTRUCTIONS = {
|
|
13165
|
+
correctness: "CORRECTNESS lens. Does the change do what the build report claims, without bugs? Hunt logic errors, off-by-one/boundary mistakes, unhandled error branches, null/undefined hazards, race conditions, and wrong assumptions about inputs. Ignore style, security, and scope \u2014 other lenses own those.",
|
|
13166
|
+
security: "SECURITY lens. Any auth/data/secret/injection risk introduced? Check for missing project_id scoping on multi-tenant SQL, RLS bypass via service role, unescaped input, leaked credentials/tokens in logs or responses, and newly-public routes (PUBLIC_PATHS). Ignore correctness/style unless it is the vector for a security issue.",
|
|
13167
|
+
wiring: "WIRING lens (AD-74 \u2014 producer\u2192store\u2192consumer). A write with no reader is NOT done. For every new value produced (state, DB column, event, field), confirm something actually CONSUMES it \u2014 grep for the reader. localStorage is a cache, never a store. Flag decorative writes, dead affordances, and green gates that guard a component nothing imports. Ignore correctness/security details \u2014 focus on whether the data path is actually connected end-to-end.",
|
|
13168
|
+
"test-quality": "TEST-QUALITY lens. Are the tests present and meaningful? A test that cannot fail is worse than none. Check that assertions test TRANSITIONS not snapshots, that a probe would actually go RED if the code broke, and that new behaviour is covered. Flag tests that assert on mocks instead of real behaviour, and missing coverage on the changed paths.",
|
|
13169
|
+
"scope-drift": "SCOPE-DRIFT lens. Does the diff match the BUILD HANDOFF scope? Flag unrelated changes, files touched outside the stated scope, new dependencies/abstractions not asked for, and \u2014 conversely \u2014 acceptance criteria from the handoff that were skipped. Ignore whether the in-scope code is correct; only judge whether it is the RIGHT set of changes."
|
|
13170
|
+
};
|
|
13171
|
+
var SYNTHESIS_CONTRACT_SHAPE = '{"verdict":"pass|warn|fail","summary":"<one-line consolidated assessment>","findings":[{"severity":"error|warning|info","file":"<path>","line":<number>,"message":"<specific issue>"}]}';
|
|
13172
|
+
var LEG_CONTRACT_SHAPE = '{"lens":"<lens-name>","verdict":"pass|warn|fail","findings":[{"severity":"error|warning|info","file":"<path>","line":<number>,"message":"<specific issue>"}]}';
|
|
13173
|
+
function legId(lens) {
|
|
13174
|
+
return `leg-${lens}`;
|
|
13175
|
+
}
|
|
13176
|
+
function buildFanoutReviewDispatchPrompt(input) {
|
|
13177
|
+
const { taskId, preset, systemPrompt, userMessage, contextBytes } = input;
|
|
13178
|
+
const lenses = REVIEW_PRESETS[preset];
|
|
13179
|
+
const n = lenses.length;
|
|
13180
|
+
const sizeNote = contextBytes !== void 0 ? ` \xB7 ~${Math.round(contextBytes / 1024)} KB context` : "";
|
|
13181
|
+
const sharedContext = `<review_rubric>
|
|
13182
|
+
${systemPrompt}
|
|
13183
|
+
</review_rubric>
|
|
13184
|
+
|
|
13185
|
+
<build_under_review>
|
|
13186
|
+
${userMessage}
|
|
13187
|
+
</build_under_review>`;
|
|
13188
|
+
const legBlocks = lenses.map((lens, i) => {
|
|
13189
|
+
const legPrompt = `You are lens ${i + 1} of ${n} in a PAPI multi-lens build review. Review the completed build below through ONE lens only.
|
|
13190
|
+
|
|
13191
|
+
LENS \u2014 ${LENS_INSTRUCTIONS[lens]}
|
|
13192
|
+
|
|
13193
|
+
CONTRACT:
|
|
13194
|
+
- The build report says what was intended; the diff is what actually changed.
|
|
13195
|
+
- Report ONLY findings your lens (${lens}) is responsible for. Do not stray into other lenses.
|
|
13196
|
+
- Return ONLY a single JSON object \u2014 no preamble, no commentary, no fences \u2014 in exactly this shape:
|
|
13197
|
+
${LEG_CONTRACT_SHAPE.replace("<lens-name>", lens)}
|
|
13198
|
+
- "pass" = no blocking issues for this lens; "warn" = minor/non-blocking; "fail" = a blocking issue this lens found. \`file\`/\`line\` are optional. Empty \`findings\` is valid when your lens is clean.
|
|
13199
|
+
|
|
13200
|
+
${sharedContext}`;
|
|
13201
|
+
return [
|
|
13202
|
+
`#### Lens ${i + 1}/${n} \u2014 ${lens} \`[${legId(lens)}]\``,
|
|
13203
|
+
"",
|
|
13204
|
+
`<<<BEGIN_LENS_PROMPT:${lens}>>>`,
|
|
13205
|
+
legPrompt,
|
|
13206
|
+
`<<<END_LENS_PROMPT:${lens}>>>`
|
|
13207
|
+
].join("\n");
|
|
13208
|
+
});
|
|
13209
|
+
const dependsOn = `[${lenses.map(legId).join(", ")}]`;
|
|
13210
|
+
const synthesisPrompt = `You are the SYNTHESIS step of a PAPI multi-lens build review.
|
|
13211
|
+
|
|
13212
|
+
depends_on = ${dependsOn}
|
|
13213
|
+
|
|
13214
|
+
You receive the JSON outputs of all ${n} specialist lens legs below. Your job:
|
|
13215
|
+
- Merge every leg's findings into ONE consolidated review.
|
|
13216
|
+
- Dedupe: collapse findings that multiple lenses raised about the same file/line/issue into a single entry (keep the highest severity).
|
|
13217
|
+
- Prioritize: order findings most-severe first (error \u2192 warning \u2192 info).
|
|
13218
|
+
- Decide ONE overall verdict: "fail" if any leg found a blocking issue, "warn" if only minor nits remain, "pass" if all legs were clean.
|
|
13219
|
+
- Return ONLY a single JSON object \u2014 no preamble, no commentary, no fences \u2014 in exactly this shape (the review_submit auto_review contract):
|
|
13220
|
+
${SYNTHESIS_CONTRACT_SHAPE}
|
|
13221
|
+
|
|
13222
|
+
<lens_leg_outputs>
|
|
13223
|
+
Paste every lens leg's JSON output here, one per line or concatenated:
|
|
13224
|
+
<<<PASTE_ALL_LEG_OUTPUTS_HERE>>>
|
|
13225
|
+
</lens_leg_outputs>`;
|
|
13226
|
+
const applyNote = `\`review_submit\` with task_id="${taskId}", stage="build-acceptance", verdict=<your decision: accept / request-changes / reject>, comments=<your reasoning>, and auto_review set to the synthesis JSON object verbatim. The synthesized verdict is a RECOMMENDATION \u2014 you make the final call.`;
|
|
13227
|
+
return [
|
|
13228
|
+
`## PAPI review_submit \u2014 Multi-Lens Fan-Out Review (${taskId} \xB7 preset: ${preset} \xB7 ${n} lens${n === 1 ? "" : "es"} + synthesis${sizeNote})`,
|
|
13229
|
+
"",
|
|
13230
|
+
"This build review fans out across specialist lenses: each lens below reviews the SAME diff in parallel, then a synthesis step dedupes their findings into one prioritized verdict. **PAPI emits this prompt \u2014 YOU (the host) run the Task calls. PAPI never executes the agents itself.**",
|
|
13231
|
+
"",
|
|
13232
|
+
"---",
|
|
13233
|
+
"",
|
|
13234
|
+
`### Step 1 \u2014 Dispatch ${n} specialist lens${n === 1 ? "" : "es"} IN PARALLEL`,
|
|
13235
|
+
"",
|
|
13236
|
+
`Make ${n} \`Task\` call${n === 1 ? "" : "s"} in a SINGLE message so they run concurrently. Each uses \`subagent_type: general-purpose\`. For each lens, pass the prompt block between its BEGIN/END markers (trimmed of the markers). Each leg returns ONLY its own tagged JSON.`,
|
|
13237
|
+
"",
|
|
13238
|
+
legBlocks.join("\n\n"),
|
|
13239
|
+
"",
|
|
13240
|
+
"### Step 2 \u2014 Synthesis (`depends_on` = ALL lens legs)",
|
|
13241
|
+
"",
|
|
13242
|
+
`Wait until ALL ${n} lens legs above have returned. The synthesis step below declares \`depends_on = ${dependsOn}\` \u2014 do NOT run it before every leg is back. Make ONE more \`Task\` call (\`subagent_type: general-purpose\`) with the block below, pasting every leg's JSON output where marked.`,
|
|
13243
|
+
"",
|
|
13244
|
+
"<<<BEGIN_SYNTHESIS_PROMPT>>>",
|
|
13245
|
+
synthesisPrompt,
|
|
13246
|
+
"<<<END_SYNTHESIS_PROMPT>>>",
|
|
13247
|
+
"",
|
|
13248
|
+
"### Step 3 \u2014 Apply the synthesized verdict",
|
|
13249
|
+
"",
|
|
13250
|
+
`When synthesis returns its JSON, surface the consolidated findings, decide your verdict, then call ${applyNote}`,
|
|
13251
|
+
"",
|
|
13252
|
+
"Do NOT post-process the synthesis JSON \u2014 the `auto_review` apply path expects it exactly as emitted."
|
|
13253
|
+
].join("\n");
|
|
13254
|
+
}
|
|
13132
13255
|
|
|
13133
13256
|
// src/lib/resolve-llm-response.ts
|
|
13134
13257
|
import { readFile as readFile3, stat } from "fs/promises";
|
|
@@ -21049,6 +21172,7 @@ async function completeBuild(adapter2, config2, taskId, input, options = {}, cli
|
|
|
21049
21172
|
completed: capitalizeCompleted(input.completed),
|
|
21050
21173
|
actualEffort: input.effort,
|
|
21051
21174
|
estimatedEffort: input.estimatedEffort,
|
|
21175
|
+
model: input.model,
|
|
21052
21176
|
surprises: input.surprises,
|
|
21053
21177
|
discoveredIssues: input.discoveredIssues,
|
|
21054
21178
|
architectureNotes: input.architectureNotes,
|
|
@@ -21985,6 +22109,11 @@ var buildExecuteTool = {
|
|
|
21985
22109
|
enum: ["XS", "S", "M", "L", "XL"],
|
|
21986
22110
|
description: "Estimated effort from the BUILD HANDOFF. Required for complete."
|
|
21987
22111
|
},
|
|
22112
|
+
model: {
|
|
22113
|
+
type: "string",
|
|
22114
|
+
maxLength: 120,
|
|
22115
|
+
description: "The model/agent that executed this build, self-reported, e.g. 'claude-opus-4' / 'gpt-5' \u2014 optional; powers attributed-intelligence analytics. PAPI never selects a model (AD-58) \u2014 report the model YOU are running as."
|
|
22116
|
+
},
|
|
21988
22117
|
surprises: {
|
|
21989
22118
|
type: "string",
|
|
21990
22119
|
maxLength: 800,
|
|
@@ -21993,7 +22122,7 @@ var buildExecuteTool = {
|
|
|
21993
22122
|
discovered_issues: {
|
|
21994
22123
|
type: "string",
|
|
21995
22124
|
maxLength: 800,
|
|
21996
|
-
description: `
|
|
22125
|
+
description: `A REAL bug or gap OUTSIDE this task's scope that needs its own task. Include severity (P0-P3). INCLUSION TEST \u2014 file it only if BOTH are true: (1) the bug would exist even if this task had never run, and (2) it is outside this task's scope. If either is false, it is NOT a discovered_issue. NEVER file a trivial in-file cleanup you noticed while editing (an em-dash tidy, a rename, a lint nit, a stray console.log) \u2014 those are not bugs, just clean them up or leave them. Good: "P2: Auth middleware doesn't validate token expiry \u2014 affects all protected routes." Bad: "Two em dashes remain in the file" / "Had to install a dependency." Use "None" if none. Required for complete. TIP: When submitting a follow-up idea for a discovered issue, include "learning:<uuid>" in the idea notes to link it to this cycle learning entry \u2014 use the UUID returned in the build completion output.`
|
|
21997
22126
|
},
|
|
21998
22127
|
architecture_notes: {
|
|
21999
22128
|
type: "string",
|
|
@@ -22279,7 +22408,7 @@ async function handleBuildExecute(adapter2, config2, args, clientName) {
|
|
|
22279
22408
|
**PRE-BUILD VERIFICATION:** Before writing any code, read these files and check if the functionality already exists:
|
|
22280
22409
|
${verificationFiles.map((f) => `- ${f}`).join("\n")}
|
|
22281
22410
|
If >80% of the scope is already implemented, call \`build_execute\` with completed="yes" and note "already built" in surprises instead of re-implementing.` : "";
|
|
22282
|
-
const chainInstruction = '\n\n---\n\n**IMPORTANT:** After implementing this task, immediately call `build_execute` again with report fields (`completed`, `effort`, `estimated_effort`, `surprises`, `discovered_issues`, `architecture_notes`) to complete the build. Do not wait for user confirmation.\n\n**Build Report Quality Bar:**\n- **surprises**: What was DIFFERENT from expected \u2014 wrong assumptions, scope changes, missing infrastructure. NOT implementation mechanics ("used X library").\n- **discovered_issues**:
|
|
22411
|
+
const chainInstruction = '\n\n---\n\n**IMPORTANT:** After implementing this task, immediately call `build_execute` again with report fields (`completed`, `effort`, `estimated_effort`, `surprises`, `discovered_issues`, `architecture_notes`) to complete the build. Do not wait for user confirmation.\n\n**Build Report Quality Bar:**\n- **surprises**: What was DIFFERENT from expected \u2014 wrong assumptions, scope changes, missing infrastructure. NOT implementation mechanics ("used X library").\n- **discovered_issues**: REAL bugs/gaps OUTSIDE this task\'s scope, with severity (P0-P3). Inclusion test: file it only if the bug would exist even if this task had never run AND it is outside this task\'s scope. NEVER a trivial in-file cleanup you noticed while editing (em-dash tidy, rename, lint nit) \u2014 those are not discovered_issues. NOT "had to install a dependency".\n- **architecture_notes**: Patterns/decisions that AFFECT FUTURE WORK. NOT "used React hooks".\n- If nothing meaningful to report for a field, use "None" \u2014 empty signal is better than noise.\n- **dead_ends**: approaches you tried and RULED OUT (with why). Ruled-out paths are first-class intelligence \u2014 send "None" only if nothing you tried failed.';
|
|
22283
22412
|
const buildDisciplineNote = "\n\n---\n\n**BUILD DISCIPLINE:**\n- **Read before you claim.** Before asserting how something works \u2014 or that it is already done \u2014 read the actual code/state. Don't rely on memory or earlier context.\n- **Sweep existing material first.** Check the docs (`doc_search` or your docs index) and prior tasks, not just whether a file exists \u2014 the work may already be covered.\n- **Ranged reads.** For large or unfamiliar files, read the relevant range rather than the whole file.";
|
|
22284
22413
|
let adSection = "";
|
|
22285
22414
|
try {
|
|
@@ -22355,6 +22484,7 @@ async function handleExecuteComplete(adapter2, config2, taskId, args, light = fa
|
|
|
22355
22484
|
const completed = args.completed;
|
|
22356
22485
|
const effort = args.effort;
|
|
22357
22486
|
const estimatedEffort = args.estimated_effort;
|
|
22487
|
+
const model = typeof args.model === "string" && args.model.trim() !== "" ? args.model.trim() : void 0;
|
|
22358
22488
|
const surprises = args.surprises;
|
|
22359
22489
|
const discoveredIssues = args.discovered_issues;
|
|
22360
22490
|
const architectureNotes = args.architecture_notes;
|
|
@@ -22410,6 +22540,7 @@ async function handleExecuteComplete(adapter2, config2, taskId, args, light = fa
|
|
|
22410
22540
|
completed,
|
|
22411
22541
|
effort: parsedEffort,
|
|
22412
22542
|
estimatedEffort: parsedEstimatedEffort,
|
|
22543
|
+
model,
|
|
22413
22544
|
surprises,
|
|
22414
22545
|
discoveredIssues,
|
|
22415
22546
|
architectureNotes,
|
|
@@ -24058,7 +24189,7 @@ var REVIEW_RUBRIC = [
|
|
|
24058
24189
|
"- Quality: tests present and meaningful, no obvious debt or dead code.",
|
|
24059
24190
|
"Be specific and cite file/line where you can. Recommend fail only for blocking issues."
|
|
24060
24191
|
].join("\n");
|
|
24061
|
-
async function
|
|
24192
|
+
async function assembleReviewContext(adapter2, config2, taskId) {
|
|
24062
24193
|
const task = await adapter2.getTask(taskId);
|
|
24063
24194
|
if (!task) {
|
|
24064
24195
|
return { ok: false, error: `Task ${taskId} not found \u2014 cannot assemble review context.` };
|
|
@@ -24091,13 +24222,13 @@ ${report}
|
|
|
24091
24222
|
|
|
24092
24223
|
${diffBlock}`;
|
|
24093
24224
|
const contextBytes = Buffer.byteLength(userMessage, "utf-8");
|
|
24094
|
-
|
|
24095
|
-
|
|
24096
|
-
|
|
24097
|
-
|
|
24098
|
-
|
|
24099
|
-
|
|
24100
|
-
});
|
|
24225
|
+
return { ok: true, userMessage, contextBytes };
|
|
24226
|
+
}
|
|
24227
|
+
async function buildReviewDispatch(adapter2, config2, taskId, preset) {
|
|
24228
|
+
const ctx = await assembleReviewContext(adapter2, config2, taskId);
|
|
24229
|
+
if (!ctx.ok) return ctx;
|
|
24230
|
+
const { userMessage, contextBytes } = ctx;
|
|
24231
|
+
const prompt2 = preset ? buildFanoutReviewDispatchPrompt({ taskId, preset, systemPrompt: REVIEW_RUBRIC, userMessage, contextBytes }) : buildSubagentDispatchPrompt({ tool: "review_submit", taskId, systemPrompt: REVIEW_RUBRIC, userMessage, contextBytes });
|
|
24101
24232
|
return { ok: true, prompt: prompt2, contextBytes };
|
|
24102
24233
|
}
|
|
24103
24234
|
var reviewListTool = {
|
|
@@ -24149,6 +24280,11 @@ var reviewSubmitTool = {
|
|
|
24149
24280
|
enum: ["inline", "subagent"],
|
|
24150
24281
|
description: `task-1864: set "subagent" (build-acceptance only) to offload code review to a fresh sub-agent. Returns a Task() invocation prompt that feeds the build report + branch diff to the sub-agent, which returns structured auto_review findings. Verdict is NOT required on this call \u2014 you call review_submit again with the human verdict + the sub-agent's auto_review. Default "inline" (record the verdict directly).`
|
|
24151
24282
|
},
|
|
24283
|
+
review_preset: {
|
|
24284
|
+
type: "string",
|
|
24285
|
+
enum: ["gate", "full", "security-focused"],
|
|
24286
|
+
description: 'task-2824 (opt-in): upgrade the sub-agent dispatch to a MULTI-LENS fan-out. Requires dispatch:"subagent" (build-acceptance only). Emits N specialist lens legs (correctness/security/wiring/test-quality/scope-drift) that review the same diff in parallel, plus a synthesis leg that dedupes their findings into ONE prioritized auto_review verdict. "gate" = correctness+wiring, "full" = all 5, "security-focused" = security+correctness+wiring. Omit for the existing single-lens review (unchanged default).'
|
|
24287
|
+
},
|
|
24152
24288
|
reviewer_confirmed: {
|
|
24153
24289
|
type: "boolean",
|
|
24154
24290
|
description: "Set to true to confirm you have reviewed the build (read the build report or the pending list via review_list) before submitting an accept verdict. Required to accept a build-acceptance review unless review_list was called in the same session within the last 15 minutes. Defense-in-depth against SUP-2026-010 (Codex prematurely accepted a task because review_list was missing from its tool surface)."
|
|
@@ -24363,11 +24499,24 @@ async function handleReviewSubmit(adapter2, config2, args) {
|
|
|
24363
24499
|
caps = {};
|
|
24364
24500
|
}
|
|
24365
24501
|
const explicitDispatch = args.dispatch === "subagent";
|
|
24502
|
+
const rawPreset = args.review_preset;
|
|
24503
|
+
const reviewPreset = typeof rawPreset === "string" && rawPreset in REVIEW_PRESETS ? rawPreset : void 0;
|
|
24504
|
+
if (rawPreset !== void 0 && !explicitDispatch) {
|
|
24505
|
+
return errorResponse('review_preset requires dispatch:"subagent" (multi-lens fan-out is only available on an explicit sub-agent dispatch).');
|
|
24506
|
+
}
|
|
24507
|
+
if (typeof rawPreset === "string" && rawPreset.length > 0 && !reviewPreset) {
|
|
24508
|
+
return errorResponse(`review_preset "${rawPreset}" is not valid. Use "gate", "full", or "security-focused".`);
|
|
24509
|
+
}
|
|
24366
24510
|
const autoDispatchOptIn = args.dispatch !== "inline" && process.env.PAPI_AUTO_DISPATCH !== "false" && isCapabilityEnabled(caps, "prReviewer");
|
|
24367
24511
|
const autoDispatchEligible = !verdict && autoDispatchOptIn;
|
|
24368
24512
|
const capabilityAutoReviewEligible = verdict === "accept" && !autoReview && autoDispatchOptIn;
|
|
24369
24513
|
if ((explicitDispatch || autoDispatchEligible || capabilityAutoReviewEligible) && stage === "build-acceptance" && taskId) {
|
|
24370
|
-
const dispatch = await buildReviewDispatch(
|
|
24514
|
+
const dispatch = await buildReviewDispatch(
|
|
24515
|
+
adapter2,
|
|
24516
|
+
config2,
|
|
24517
|
+
taskId,
|
|
24518
|
+
explicitDispatch ? reviewPreset : void 0
|
|
24519
|
+
);
|
|
24371
24520
|
if (!dispatch.ok) {
|
|
24372
24521
|
if (explicitDispatch) return errorResponse(dispatch.error);
|
|
24373
24522
|
} else if (explicitDispatch || capabilityAutoReviewEligible || dispatch.contextBytes > REVIEW_DISPATCH_THRESHOLD) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@papi-ai/server",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.61",
|
|
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",
|