@sagentlab/navarch-runtime 0.1.95 → 0.1.97

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/delivery.cjs CHANGED
@@ -146,6 +146,10 @@ function describeBranch(branch) {
146
146
  * task.
147
147
  */
148
148
  function renderDeliveryCorrectionPrompt(args) {
149
+ const report = args.previousReport.trim();
150
+ const clippedReport = report.length > 8_000
151
+ ? `${report.slice(0, 8_000)}\n\n[... truncated]`
152
+ : report;
149
153
  return [
150
154
  args.originalPrompt.trim(),
151
155
  "",
@@ -157,10 +161,26 @@ function renderDeliveryCorrectionPrompt(args) {
157
161
  "so your earlier edits, commits, and branch are all still here — start with `git status` and",
158
162
  "`git log --oneline` and continue from there rather than redoing the work.",
159
163
  "",
160
- "Finish the delivery chain: commit the work, push the branch, and open the pull request.",
161
- "If part of the task genuinely cannot be completed, still deliver what does work as a pull request",
162
- "and state plainly in the description what is missing and why.",
164
+ "Inspect tracked and untracked changes before deciding what is undelivered work. Preserve required",
165
+ "evidence in task artifacts, remove only temporary files you created (such as `.review-*/` scratch",
166
+ "directories), and restore only tracked edits you made solely for local checks. Do not delete",
167
+ "unfamiliar or pre-existing changes, hide leftovers with ignore rules, or commit scratch files.",
168
+ ...(args.taskType === "review"
169
+ ? [
170
+ "This is a read-only review task. The generic delivery failure does not authorize commits,",
171
+ "pushes, rebases, merges, or a new PR. A dirty worktree may contain only review scratch files.",
172
+ "Check whether the native review already exists for this task and reviewed head. If it does,",
173
+ "reuse that review and its matching attestation; do not file a duplicate or implement findings.",
174
+ "If it does not, finish filing the review required by the original task. Leave a clean worktree.",
175
+ ]
176
+ : [
177
+ "Follow the original task's delivery contract. If it requires a PR, commit the intended work,",
178
+ "push the branch, and open or update the PR. A report-only task does not need a new PR.",
179
+ "If part of a PR task cannot be completed, deliver what does work and describe the gap.",
180
+ ]),
163
181
  "",
164
- "This session's worktree is deleted when the session ends. Work that is not pushed is lost.",
182
+ "Your final report replaces the previous one. Restate it in full in the required format, preserving",
183
+ "the verdict, reviewed head, findings, and validation limitations. Do not claim delivery you cannot verify.",
184
+ ...(clippedReport ? ["", "### Previous turn's final report", "", clippedReport] : []),
165
185
  ].join("\n");
166
186
  }
@@ -9,6 +9,7 @@ exports.extractUsageFromCodexEvents = extractUsageFromCodexEvents;
9
9
  exports.extractFinalMessageFromCodexEvents = extractFinalMessageFromCodexEvents;
10
10
  exports.leadingVerificationVerdict = leadingVerificationVerdict;
11
11
  exports.leadWithReviewFixMarker = leadWithReviewFixMarker;
12
+ exports.leadWithReviewAttestation = leadWithReviewAttestation;
12
13
  exports.mapExitCondition = mapExitCondition;
13
14
  /**
14
15
  * Leading text of every report for a turn the coding agent CLI refused because
@@ -242,6 +243,61 @@ function leadWithReviewFixMarker(report) {
242
243
  .trim();
243
244
  return rest ? `${line}\n\n${rest}` : line;
244
245
  }
246
+ const REVIEW_ATTESTATION = /^(?:\[(Approve|Code Review: Blocking|Code Review: Comment)\]\s+)?NAVARCH_REVIEW_ATTESTATION:\s*(approve|request_changes|comment)\s+([0-9a-f]{40}|[0-9a-f]{64})(?:\s|$)/i;
247
+ const REVIEW_PREFIXES = {
248
+ approve: "[approve]",
249
+ request_changes: "[code review: blocking]",
250
+ comment: "[code review: comment]",
251
+ };
252
+ function parseReviewAttestation(line) {
253
+ const match = REVIEW_ATTESTATION.exec(line.trim());
254
+ if (!match)
255
+ return null;
256
+ const verdict = (match[2] ?? "").toLowerCase();
257
+ if (match[1] && `[${match[1]}]`.toLowerCase() !== REVIEW_PREFIXES[verdict])
258
+ return null;
259
+ return { verdict, headSha: (match[3] ?? "").toLowerCase() };
260
+ }
261
+ /**
262
+ * Moves a review's `NAVARCH_REVIEW_ATTESTATION` line to the top of the report.
263
+ * The control plane accepts it only as the first line
264
+ * (lib/navarch/review-attestation.ts). Claude often writes a sentence of
265
+ * preamble before it, and every such review was rejected with
266
+ * `review_attestation_required` and needed a correction turn. Kept in step
267
+ * with leadWithPlatformReviewAttestation there; this package cannot import
268
+ * it. Two lines that disagree are left for the control plane to reject.
269
+ */
270
+ function leadWithReviewAttestation(report) {
271
+ if (parseReviewAttestation(report))
272
+ return report;
273
+ const lines = report.split("\n");
274
+ const claims = lines
275
+ .map((line, index) => ({ index, line: line.trim(), parsed: parseReviewAttestation(line) }))
276
+ .filter((entry) => entry.parsed !== null);
277
+ const first = claims[0];
278
+ if (!first)
279
+ return report;
280
+ const agree = claims.every((entry) => entry.parsed.verdict === first.parsed.verdict && entry.parsed.headSha === first.parsed.headSha);
281
+ if (!agree)
282
+ return report;
283
+ const claimLines = new Set(claims.map((entry) => entry.index));
284
+ const rest = lines
285
+ .filter((_, index) => !claimLines.has(index))
286
+ .join("\n")
287
+ .replace(/\n{3,}/g, "\n\n")
288
+ .trim();
289
+ return rest ? `${first.line}\n\n${rest}` : first.line;
290
+ }
291
+ /**
292
+ * True when the report opens with `Build outcome: FAILED|BLOCKED`. Also
293
+ * accepts `Task outcome:` and Markdown emphasis, which is how agents write
294
+ * "report a failed completion". Kept in step with declaresBuildFailure in
295
+ * lib/navarch/build-outcome.ts.
296
+ */
297
+ function declaresBuildFailure(report) {
298
+ const firstLine = report.split(/\r?\n/).map((line) => line.trim()).find(Boolean) ?? "";
299
+ return /^(?:Build|Task) outcome:[*_`~]*\s*[*_`~]*(?:FAILED|BLOCKED)(?![a-z0-9_])/i.test(firstLine.replace(/^(?:#{1,6}\s+|>\s*|[*_`~]+\s*)+/, ""));
300
+ }
245
301
  function summarize(text, maxLen = 500) {
246
302
  const trimmed = text.trim();
247
303
  if (!trimmed)
@@ -341,7 +397,8 @@ function mapExitCondition(result) {
341
397
  // falls back to raw stdout when neither is available (see
342
398
  // parseClaudeJsonResult's doc comment).
343
399
  const reportText = result.reportText ?? parsedJson?.result ?? result.stdout;
344
- const reportSummary = summarize(leadWithReviewFixMarker(reportText)) || "Adapter completed with no report text.";
400
+ const reportSummary = summarize(leadWithReviewAttestation(leadWithReviewFixMarker(reportText))) ||
401
+ "Adapter completed with no report text.";
345
402
  // A verify agent's FAIL/BLOCKED verdict is a successful agent run whose
346
403
  // conclusion is that the delivery did not pass. The completion API only
347
404
  // accepts those verdicts with a failed outcome, so map them to a failed
@@ -362,7 +419,7 @@ function mapExitCondition(result) {
362
419
  // Build agents also use an explicit outcome marker. A zero process exit
363
420
  // means the conversation finished, not that the requested build succeeded.
364
421
  if (/^blocked(?:\s|:|$)/i.test(reportText.trim()) ||
365
- /^Build outcome:\s*(?:FAILED|BLOCKED)\b/i.test(reportText.trim())) {
422
+ declaresBuildFailure(reportText)) {
366
423
  return {
367
424
  leaseOutcome: "failed",
368
425
  exitStatus: "failed",
package/dist/prompt.cjs CHANGED
@@ -5,7 +5,7 @@ exports.renderGuidanceCorrectionPrompt = renderGuidanceCorrectionPrompt;
5
5
  exports.renderCompletionRemediationPrompt = renderCompletionRemediationPrompt;
6
6
  exports.renderHostedCheckpointNote = renderHostedCheckpointNote;
7
7
  const CODE_GRAPH_GUIDANCE = "For JS/TS dependency inspection, the runtime provides `navarch-runtime code-graph --query <symbol-or-file> --mode search|callers|callees|impact --commit HEAD`. If the runtime is not on PATH, use its installed entry point; do not install another copy mid-task. Results describe committed source and include commit/freshness warnings; inspect current files for uncommitted changes and unresolved dependencies.";
8
- const PROCESS_GUIDANCE = "Process management: this host may run other agent sessions. Keep the PID or tool handle of each preview server you start and stop only that owned process. Never use broad process-name or command-line matching (pkill, killall) to clean up servers: the agent launcher carries the task prompt in its arguments and can match those patterns, terminating your own session. Use a different port when a port is occupied by a process you do not own. Keep scratch files in the current worktree; paths in previous transcripts belong to earlier sessions.";
8
+ const PROCESS_GUIDANCE = "Process management: this host may run other agent sessions. Keep the PID or tool handle of each preview server you start and stop only that owned process. Never use broad process-name or command-line matching (pkill, killall) to clean up servers: the agent launcher carries the task prompt in its arguments and can match those patterns, terminating your own session. Use a different port when a port is occupied by a process you do not own. Keep scratch files in the current worktree; paths in previous transcripts belong to earlier sessions. Before your final report, inspect `git status --short`, including untracked files. Preserve required evidence in task artifacts, then remove only temporary files you created and restore only tracked edits you made solely for local checks. Do not delete unfamiliar or pre-existing changes, hide leftovers with ignore rules, or commit scratch files merely to make the worktree clean. Review tasks deliver a native review and attestation, never commits, pushes, or a new PR.";
9
9
  /** Overrides the playbooks' "default branch" PR base when the project sets a working branch. */
10
10
  function workingBranchNote(workingBranch) {
11
11
  if (!workingBranch)
package/dist/session.cjs CHANGED
@@ -706,6 +706,10 @@ async function runClaimedSession(deps, claimed, sessionId, lifecycle) {
706
706
  `restarting agent turn ${deliveryCorrectionRetries}/${DELIVERY_CORRECTION_RETRIES} in the same worktree.`);
707
707
  nextPrompt = (0, delivery_cjs_1.renderDeliveryCorrectionPrompt)({
708
708
  originalPrompt: runPrompt,
709
+ taskType: task.task_type,
710
+ // The completion summary is capped at 500 characters. Preserve
711
+ // the final prose from adapters that only return stdout as well.
712
+ previousReport: (0, redact_cjs_1.redactText)(result.reportText ?? (0, exit_conditions_cjs_1.parseClaudeJsonResult)(result.stdout)?.result ?? result.stdout, registry.list()),
709
713
  reason: delivery.reason,
710
714
  attempt: deliveryCorrectionRetries,
711
715
  maxAttempts: DELIVERY_CORRECTION_RETRIES,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sagentlab/navarch-runtime",
3
- "version": "0.1.95",
3
+ "version": "0.1.97",
4
4
  "description": "Navarch machine-side session manager: claims delivery tasks and runs them through local coding agents.",
5
5
  "type": "commonjs",
6
6
  "license": "MIT",