@miraland-labs/conduit-bridge 0.9.11 → 0.9.12

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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Local Bridge CLI for [Conduit](https://github.com/miralandlabs/conduit). Connects a computer to one organization, claims work, and drives a local agent.
4
4
 
5
- **Package version:** `0.9.11` — heartbeat protocol 2 requires a clean workspace plus a ready, versioned driver lane before dispatch. Cursor assignments with `external_network` allow-list `WebFetch(*)` and pass `--force` (required for headless fetch); research-only networked runs also deny `Shell(*)` / `Write(**)`. Attempt worktrees fetch/start from the initiative base when the source tip is behind or history was rewritten, without resetting the source checkout. Also includes **ops** helpers for macOS / Linux / Windows, LaunchAgent/systemd **PATH** for `~/.local/bin`, disconnect/disengage, multi-driver lanes, shared slots **1–4**, worktrees, and optional `--ensure-checkout`. Protocol 1 heartbeats remain compatible for presence but cannot receive work.
5
+ **Package version:** `0.9.12` — heartbeat protocol 2 requires a clean workspace plus a ready, versioned driver lane before dispatch. Cursor assignments with `external_network` allow-list `WebFetch(*)` and pass `--force` (required for headless fetch); research-only networked runs also deny `Shell(*)` / `Write(**)`. Artifact evidence digests normalize bare 64-hex to `sha256:<hex>`. Attempt worktrees fetch/start from the initiative base when the source tip is behind or history was rewritten, without resetting the source checkout. Also includes **ops** helpers for macOS / Linux / Windows, LaunchAgent/systemd **PATH** for `~/.local/bin`, disconnect/disengage, multi-driver lanes, shared slots **1–4**, worktrees, and optional `--ensure-checkout`. Protocol 1 heartbeats remain compatible for presence but cannot receive work.
6
6
 
7
7
  ## Prerequisites
8
8
 
package/dist/driver.js CHANGED
@@ -174,7 +174,7 @@ export function buildAssignmentPrompt(context) {
174
174
  // `git status` stays clean — which is the point for a content pack, and mandatory for
175
175
  // anything binary.
176
176
  "- This assignment delivers an artifact, not repository content. Write your output under `.conduit/artifacts/` — that path is excluded from git, so do not commit anything and do not report a head_commit.",
177
- "- Publish the artifact to its destination and report each output in your evidence with the published URL and a sha256 digest. An artifact nobody can fetch is not a delivery.",
177
+ "- Publish the artifact to its destination and report each output in your evidence with the published HTTPS URL and digest exactly as `sha256:` plus the 64-character hex hash (bare hex from shasum is normalized, but prefer the prefixed form). An artifact nobody can fetch is not a delivery.",
178
178
  ]
179
179
  : ["- You have no repository write authority for this assignment. Do not create, modify, or commit any file; a delivery reporting repository changes will be rejected. Record all findings, verification output, and conclusions in your final report instead."]), "- Never merge, deploy, force-push, push to protected branches, or touch production.", `- Hard-denied commands (all drivers): ${deniedCommands.join("; ")}.`, "- Do not invent evidence. Report unknown when you could not verify a criterion.",
180
180
  // A met claim with nothing backing it is rejected server-side ("Met acceptance criteria require
@@ -222,6 +222,19 @@ export function parseAgentReport(text, acceptance) {
222
222
  }
223
223
  return { ...parsed.data, acceptance_results: parsed.data.acceptance_results.map((item) => ({ ...item, evidence_artifact_ids: [] })) };
224
224
  }
225
+ /**
226
+ * Artifact publication receipts require `sha256:<64 hex>`. Agents often paste bare `shasum` output;
227
+ * accept that and canonicalize. Already-prefixed digests pass through (case-normalized hex).
228
+ */
229
+ export function normalizeEvidenceDigest(digest) {
230
+ const trimmed = digest.trim();
231
+ const prefixed = /^sha256:([0-9a-f]{64})$/i.exec(trimmed);
232
+ if (prefixed)
233
+ return `sha256:${prefixed[1].toLowerCase()}`;
234
+ if (/^[0-9a-f]{64}$/i.test(trimmed))
235
+ return `sha256:${trimmed.toLowerCase()}`;
236
+ return trimmed;
237
+ }
225
238
  /**
226
239
  * Tolerate benign agent-output noise before strict validation: drop empty/whitespace-only entries from
227
240
  * string arrays and remove empty optional scalars, so a single stray "" does not fail an otherwise-valid
@@ -251,6 +264,8 @@ function sanitizeReportShape(raw) {
251
264
  // Agents emit null/"" for optional fields they have no value for — treat as absent.
252
265
  if ("digest" in evidence && (typeof evidence.digest !== "string" || evidence.digest.trim() === ""))
253
266
  delete evidence.digest;
267
+ else if (typeof evidence.digest === "string")
268
+ evidence.digest = normalizeEvidenceDigest(evidence.digest);
254
269
  // Drop non-URL / empty uris so an optional bad uri doesn't fail the whole report.
255
270
  if ("uri" in evidence && (typeof evidence.uri !== "string" || !z.string().url().max(4_000).safeParse(evidence.uri).success))
256
271
  delete evidence.uri;
package/dist/execution.js CHANGED
@@ -2,7 +2,7 @@ import { createHash } from "node:crypto";
2
2
  import { z } from "zod";
3
3
  import { ConduitRequestError } from "./client.js";
4
4
  import { redactSecrets } from "./config.js";
5
- import { DRIVERS, agentReportTemplate, buildAssignmentPrompt, evidenceKinds, fuelEndpoint, parseAgentReport, pickModelCandidate, tierForRisk } from "./driver.js";
5
+ import { DRIVERS, agentReportTemplate, buildAssignmentPrompt, evidenceKinds, fuelEndpoint, normalizeEvidenceDigest, parseAgentReport, pickModelCandidate, tierForRisk } from "./driver.js";
6
6
  import { pickDriverForClaim, resolveDriverFuel } from "./drivers.js";
7
7
  import { attemptWorktreePath, createAttemptWorktree, proveResumeWorktree, quarantineAttemptWorktree, removeAttemptWorktree, } from "./attempt-worktree.js";
8
8
  import { buildWorkspaceBrief, ensureCommitAvailable, normalizeRepositoryUrl, resolveAttemptStartCommit } from "./brief.js";
@@ -629,9 +629,9 @@ async function prepareDelivery(client, attemptId, taskId, report) {
629
629
  // Publication receipts require a digest on every acceptance artifact. Textual agent
630
630
  // evidence has no file to hash, so default to a canonical content digest of the
631
631
  // evidence itself — deterministic and verifiable against the stored metadata.
632
- const digest = item.digest ?? `sha256:${createHash("sha256")
632
+ const digest = normalizeEvidenceDigest(item.digest ?? `sha256:${createHash("sha256")
633
633
  .update(JSON.stringify({ kind: item.kind, name: item.name, details: item.details, acceptance_criteria: item.acceptance_criteria }))
634
- .digest("hex")}`;
634
+ .digest("hex")}`);
635
635
  const response = await client.attemptRequest(taskId, "artifacts", {
636
636
  kind: item.kind, name: item.name, uri, digest,
637
637
  metadata: { details: item.details, acceptance_criteria: item.acceptance_criteria },
@@ -666,7 +666,10 @@ export function validateDeliveryReport(report, spec, grants = []) {
666
666
  const published = report.evidence.some((item) => {
667
667
  if (!["preview", "research", "documentation"].includes(item.kind))
668
668
  return false;
669
- if (!item.uri || !item.digest || !/^sha256:[0-9a-f]{64}$/i.test(item.digest))
669
+ if (!item.uri || !item.digest)
670
+ return false;
671
+ const digest = normalizeEvidenceDigest(item.digest);
672
+ if (!/^sha256:[0-9a-f]{64}$/i.test(digest))
670
673
  return false;
671
674
  try {
672
675
  const protocol = new URL(item.uri).protocol;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miraland-labs/conduit-bridge",
3
- "version": "0.9.11",
3
+ "version": "0.9.12",
4
4
  "description": "Conduit Bridge CLI — join, connect, disconnect, multi-driver lanes, and run Claude Code / Codex / Cursor / OpenCode / Kiro / Antigravity agents for a Conduit organization",
5
5
  "type": "module",
6
6
  "bin": {