@miraland-labs/conduit-bridge 0.16.182 → 0.16.185

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/cli.js CHANGED
@@ -676,7 +676,9 @@ async function runner() {
676
676
  if (workspace && onlineDriverIds(config).length && !gateRehearsalRunning) {
677
677
  // Read the workspace again, then publish it. The last brief stands if the read fails.
678
678
  const publishWorkspaceState = async (options = {}) => {
679
- const refresh = await reportedRefresh(workspace, options);
679
+ // Not while an investigation runs: its observation-only check compares the source checkout
680
+ // before and after, and the runner's own fast-forward must not fail that check (CR18).
681
+ const refresh = investigationRunning ? lastRefresh?.result ?? null : await reportedRefresh(workspace, options);
680
682
  const currentBrief = await buildWorkspaceBrief(workspace).catch(() => brief);
681
683
  const preflight = await cachedBridgePreflight({ config, workspace, managedRoot, brief: currentBrief ?? undefined, refresh, agentTimeoutMs: timeoutMs }, options);
682
684
  const hb = await heartbeat(client, config, workspace, currentBrief, preflight, undefined, bootstrapResult);
@@ -687,11 +689,17 @@ async function runner() {
687
689
  };
688
690
  // Observation runs before authoring: an owner waiting on an answer should not queue behind
689
691
  // a long delivery, and the control plane already counted this slot as busy.
690
- progressed = await executeNextInvestigation(client, config, workspace, brief, timeoutMs, {
691
- managedRoot: hb.on_shift?.managed_workspace_root ?? null,
692
- heartbeat: publishHeartbeat,
693
- heartbeatIntervalMs: intervalMs,
694
- }) || progressed;
692
+ investigationRunning = true;
693
+ try {
694
+ progressed = await executeNextInvestigation(client, config, workspace, brief, timeoutMs, {
695
+ managedRoot: hb.on_shift?.managed_workspace_root ?? null,
696
+ heartbeat: publishHeartbeat,
697
+ heartbeatIntervalMs: intervalMs,
698
+ }) || progressed;
699
+ }
700
+ finally {
701
+ investigationRunning = false;
702
+ }
695
703
  progressed = await pumpExecutionSlots(client, config, workspace, brief, timeoutMs, {
696
704
  heartbeat: publishHeartbeat,
697
705
  beforeClaim: async (driverId) => {
@@ -723,6 +731,8 @@ async function runner() {
723
731
  }
724
732
  /** True while the gate rehearsal runs in the background; the loop keeps beating but claims nothing. */
725
733
  let gateRehearsalRunning = false;
734
+ /** An observation fingerprints the source checkout; a fast-forward under it reads as the observer writing. */
735
+ let investigationRunning = false;
726
736
  /** The rehearsals the heartbeat reports, one per on-shift repository; empty reports no field. */
727
737
  let reportedGateRehearsals = [];
728
738
  /** The last on-shift snapshot, so the next cycle knows every repository this computer serves. */
package/dist/driver.js CHANGED
@@ -2021,6 +2021,8 @@ export function untrustedCodeEnvironment(scratchHome) {
2021
2021
  GIT_SSH_COMMAND: "ssh -F /dev/null -o BatchMode=yes -o IdentitiesOnly=yes -o IdentityAgent=none -i /dev/null",
2022
2022
  };
2023
2023
  }
2024
+ /** Where a bwrap gate sees its TMPDIR; /tmp is a fresh tmpfs per spawn, so the name never collides. */
2025
+ export const SANDBOX_TEMP = "/tmp/gate";
2024
2026
  /** Pure spawn projection; parent mounts precede their writable children. */
2025
2027
  export function buildUntrustedCodeSpawn(input, host) {
2026
2028
  const direct = { command: input.command, argv: input.argv, cwd: input.cwd, env: input.env };
@@ -2034,6 +2036,9 @@ export function buildUntrustedCodeSpawn(input, host) {
2034
2036
  const argv = ["--die-with-parent", "--new-session", "--unshare-net", "--unshare-pid", "--unshare-ipc", "--unshare-uts",
2035
2037
  "--ro-bind", "/", "/", "--dev", "/dev", "--proc", "/proc",
2036
2038
  ...["/tmp", "/run", "/home", "/root"].flatMap((path) => ["--tmpfs", path]),
2039
+ // Before every path bind: a nested sandbox's cwd and home live under /tmp/gate, and a later
2040
+ // mount here would shadow them (CR17g, 2026-10-22: 8 of Conduit's own gate tests inside a gate).
2041
+ ...(host.tempMount ? ["--bind", host.tempMount.source, host.tempMount.target] : []),
2037
2042
  ...(host.sourceRepository ? ["--ro-bind", host.sourceRepository, host.sourceRepository] : []),
2038
2043
  ...(host.toolchainRead ?? []).flatMap((path) => ["--ro-bind", path, path]),
2039
2044
  ...(rootWorkspace ? ["--bind", input.cwd, input.cwd] : []),
@@ -2202,8 +2207,12 @@ export async function untrustedCodeSpawn(input) {
2202
2207
  const home = await realpath(input.env.HOME);
2203
2208
  const temp = join(home, "tmp");
2204
2209
  await mkdir(temp, { recursive: true });
2210
+ // CR17f (2026-10-22): under an attempt worktree this temp is ~150 bytes deep, past the 108-byte
2211
+ // Unix socket limit, and a listen there fails or collides. bwrap shows it at a short path instead.
2212
+ const tempMount = sandbox.os_sandbox === "bwrap" ? { source: temp, target: SANDBOX_TEMP } : undefined;
2213
+ const visibleTemp = tempMount?.target ?? temp;
2205
2214
  const env = { ...input.env, PATH: (await sandboxPathDirectories(input.env)).join(delimiter), HOME: home, XDG_CONFIG_HOME: join(home, "config"),
2206
- XDG_CACHE_HOME: join(home, "cache"), XDG_DATA_HOME: join(home, "data"), TMPDIR: temp, TMP: temp, TEMP: temp };
2215
+ XDG_CACHE_HOME: join(home, "cache"), XDG_DATA_HOME: join(home, "data"), TMPDIR: visibleTemp, TMP: visibleTemp, TEMP: visibleTemp };
2207
2216
  const writable = [cwd, home, temp];
2208
2217
  for (const key of ["CARGO_TARGET_DIR", "CARGO_HOME"]) {
2209
2218
  const path = input.env[key];
@@ -2218,7 +2227,7 @@ export async function untrustedCodeSpawn(input) {
2218
2227
  toolchainRead.push(await realpath(input.env.RUSTUP_HOME));
2219
2228
  const repository = await sandboxRepositoryPaths(cwd);
2220
2229
  return buildUntrustedCodeSpawn({ ...input, command, cwd, env, writable }, {
2221
- ...sandbox, home: await realpath(homedir()), toolchainRead, ...repository, ephemeral: await sandboxNodeScratch(cwd, repository.sourceRepository),
2230
+ ...sandbox, home: await realpath(homedir()), toolchainRead, ...repository, ephemeral: await sandboxNodeScratch(cwd, repository.sourceRepository), tempMount,
2222
2231
  });
2223
2232
  }
2224
2233
  const sandboxExecFile = promisify(execFile);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miraland-labs/conduit-bridge",
3
- "version": "0.16.182",
3
+ "version": "0.16.185",
4
4
  "description": "Conduit Bridge CLI — 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": {