@miraland-labs/conduit-bridge 0.16.101 → 0.16.102

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/execution.js CHANGED
@@ -28,7 +28,7 @@ const execFileAsync = promisify(execFile);
28
28
  import { captureVerificationFailure, detectGateRanNothing, ensureTestEvidence, needsTestEvidence, runBoundedVerificationCommand, verificationEvidenceCommands, VerificationGateRanNothingError } from "./ensure-test-evidence.js";
29
29
  import { ensureChangeEvidence } from "./ensure-change-evidence.js";
30
30
  import { ensureNormativeEvidence } from "./ensure-normative-evidence.js";
31
- import { changedPathsSince, compareWorktreeState, worktreeStateFingerprint, worktreeWrittenPaths } from "./git-witness.js";
31
+ import { changedPathsSince, compareWorktreeState, diffStatSince, worktreeStateFingerprint, worktreeWrittenPaths } from "./git-witness.js";
32
32
  import { assertNormativeRefsMaterialized, checkNormativeMarkers, materializeNormativeRefs, NORMATIVE_MARKER_PREFIX, NORMATIVE_REF_PREFIX, parseNormativeRefs, } from "./normative-refs.js";
33
33
  import { checkIntegrationObligations, INTEGRATION_OBLIGATION_PREFIX, parseIntegrationObligations, } from "./integration-obligations.js";
34
34
  /** Keep a Mac awake only while an assignment is active; display sleep remains allowed. */
@@ -1717,6 +1717,11 @@ async function runAttempt(client, config, driver, workspace, brief, taskId, watc
1717
1717
  : null;
1718
1718
  // The vendor named the model as the cause, so the model is what the retry must change. The
1719
1719
  // model rides in the prefix: the control plane cannot read Bridge's selection any other way.
1720
+ const diffStat = verificationDetail && attemptWorkspace && startCommit
1721
+ ? await diffStatSince(attemptWorkspace, startCommit)
1722
+ .then((stat) => stat?.slice(0, 8_000) ?? null)
1723
+ .catch(() => null)
1724
+ : null;
1720
1725
  const abortPrefix = agentModelAbortPrefix(selection.model);
1721
1726
  const modelAborted = agentModelAborted(`${agentMessage}\n${result.signal?.stderr_tail ?? ""}`);
1722
1727
  // T52: the epoch's second abort is not a retryable model swap — the first one already bought
@@ -1724,7 +1729,7 @@ async function runAttempt(client, config, driver, workspace, brief, taskId, watc
1724
1729
  // "Agent Looping Detected" runs on the cursor CLI default). Hold on the tier instead.
1725
1730
  const bindingRequired = modelAborted && !verificationDetail && modelBindingRequired(selection);
1726
1731
  const message = verificationDetail
1727
- ? `Verification failed after the agent run.\n${verificationDetail}`
1732
+ ? `Verification failed after the agent run.\n${verificationDetail}${diffStat ? `\n\nChanged files:\n${diffStat}` : ""}`
1728
1733
  : bindingRequired
1729
1734
  ? `${modelBindingRequiredPrefix(selection.tier, driver.name)}${agentMessage}`
1730
1735
  : modelAborted ? `${abortPrefix}${agentMessage}` : agentMessage;
@@ -1744,7 +1749,7 @@ async function runAttempt(client, config, driver, workspace, brief, taskId, watc
1744
1749
  ? { phase: "agent", witness: "vendor", kind: "quota", vendor_message: agentMessage.slice(0, 2_000) }
1745
1750
  : result.signal
1746
1751
  ? verificationDetail
1747
- ? { ...result.signal, phase: "verification", witness: "bridge", stderr_tail: undefined, stdout_tail: undefined }
1752
+ ? { ...result.signal, phase: "verification", witness: "bridge", stderr_tail: undefined, stdout_tail: undefined, ...(diffStat ? { diff_stat: diffStat } : {}) }
1748
1753
  : result.signal
1749
1754
  : undefined;
1750
1755
  const response = await queueTerminal(client, taskId, { action: "fail", body: {
@@ -2172,8 +2177,13 @@ async function runAttempt(client, config, driver, workspace, brief, taskId, watc
2172
2177
  // exact tree and send the witness marker that arms Conductor diagnosis. Treating it as a
2173
2178
  // delivery-envelope defect would stop before Invariant 23 ever ran.
2174
2179
  const verificationFailed = /^Agent report: Verification failed \(/.test(message);
2180
+ const diffStat = verificationFailed && attemptWorkspace
2181
+ ? await diffStatSince(attemptWorkspace, deliveryBaseCommit)
2182
+ .then((stat) => stat?.slice(0, 8_000) ?? null)
2183
+ .catch(() => null)
2184
+ : null;
2175
2185
  const classified = verificationFailed
2176
- ? { retryable: true, error: `Verification failed after the agent run.\n${message}` }
2186
+ ? { retryable: true, error: `Verification failed after the agent run.\n${message}${diffStat ? `\n\nChanged files:\n${diffStat}` : ""}` }
2177
2187
  // classifyFinalizeFailure: forge transport → retryable; contract/environment/unknown → fail
2178
2188
  // closed (unknown prefixed as "Bridge finalize interrupted", not laundered as contract).
2179
2189
  : classifyFinalizeFailure(message);
@@ -2184,6 +2194,12 @@ async function runAttempt(client, config, driver, workspace, brief, taskId, watc
2184
2194
  body: {
2185
2195
  error: classified.error,
2186
2196
  retryable: classified.retryable,
2197
+ ...(verificationFailed ? { signal: {
2198
+ phase: "verification",
2199
+ witness: "bridge",
2200
+ kind: "verification_failed",
2201
+ ...(diffStat ? { diff_stat: diffStat } : {}),
2202
+ } } : {}),
2187
2203
  // A rework's own PR may already be open (ensureDeliveryPullRequest ran before this
2188
2204
  // gate). Carry the URL so the control plane can close it instead of littering.
2189
2205
  ...(report.pull_request_url ? { pull_request_url: report.pull_request_url } : {}),
@@ -24,6 +24,8 @@ export const failureSignalSchema = z.object({
24
24
  paths: z.array(z.string().max(300)).max(20).optional(),
25
25
  /** The base commit the dry run ran against, when a gate already fails there. */
26
26
  base_commit: z.string().max(200).optional(),
27
+ /** Short git diff --stat of files modified in the attempt worktree. */
28
+ diff_stat: z.string().max(8_000).optional(),
27
29
  exit_code: z.number().int().nullable().optional(),
28
30
  /** The vendor envelope's own status, e.g. agy's "ERROR". */
29
31
  vendor_status: z.string().max(200).optional(),
@@ -123,11 +123,20 @@ export function compareWorktreeState(before, after) {
123
123
  /** Short stat summary for change evidence artifacts. */
124
124
  export async function diffStatSince(worktree, startCommit) {
125
125
  try {
126
- const { stdout } = await execFileAsync("git", ["-C", worktree, "diff", "--stat", `${startCommit}..HEAD`], {
127
- timeout: 30_000,
128
- maxBuffer: 2_000_000,
129
- });
130
- const text = stdout.trim();
126
+ const [{ stdout }, { stdout: untracked }] = await Promise.all([
127
+ execFileAsync("git", ["-C", worktree, "diff", "--stat", startCommit], {
128
+ timeout: 30_000,
129
+ maxBuffer: 2_000_000,
130
+ }),
131
+ execFileAsync("git", ["-C", worktree, "ls-files", "--others", "--exclude-standard", "-z"], {
132
+ timeout: 30_000,
133
+ maxBuffer: 2_000_000,
134
+ encoding: "buffer",
135
+ }),
136
+ ]);
137
+ const untrackedLines = untracked.toString("utf8").split("\0").filter(Boolean)
138
+ .map((path) => ` ${path} | untracked`);
139
+ const text = [stdout.trim(), ...untrackedLines].filter(Boolean).join("\n");
131
140
  return text || null;
132
141
  }
133
142
  catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miraland-labs/conduit-bridge",
3
- "version": "0.16.101",
3
+ "version": "0.16.102",
4
4
  "description": "Conduit Bridge CLI \u2014 join, connect, disconnect, multi-driver lanes, and run Claude Code / Codex / Cursor / OpenCode / Pi / Kiro / Antigravity / Grok Build agents for a Conduit organization",
5
5
  "type": "module",
6
6
  "bin": {