@miraland-labs/conduit-bridge 0.16.121 → 0.16.127

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.16.95` — Conduit-fuel lanes bind organization aliases (T144), the Anthropic base URL is the origin (T148), the investigation lane resolves its model (T154); a hosted container image lives under `hosted/` (docs/HOSTED_RUNNER.md). Earlier (0.16.27) — work-package execution budgets reach every agent turn, are bounded by the machine ceiling, and expose their effective source for operations. Local-fuel provider refusals make the affected lane unavailable instead of repeatedly spending attempts; an operator who changes the lane's account or plan can invalidate that observation with `ops quota-clear <driver>`. Bridge discovers bounded repository verification commands, including Make targets `test`, `check`, `verify`, `replay`, `typecheck`, `lint`, and `build`. `ops disconnect` asks before it removes the runner service and clears credentials; pass `--yes` to skip the question. `ops.env` is enrollment/bootstrap defaults only: an explicit workspace does not inherit an old repository, and project switches do not rewrite global project state. `ops enroll` exchanges a single-use token, registers the machine, binds project affinity, provisions fuel keys, brings detected drivers online, and starts the runner in one command. On Linux, `ops install` refuses any effective systemd drop-in. A switch intent remains queued until the target runner heartbeat proves Bound. After every Bridge publish, operators must re-run `ops install` (LaunchAgent pins an absolute `cli.js`).
5
+ **Package version:** `0.16.125` — the workspace brief reports `declared_demonstration` so the planner knows whether the repository can show itself (KERNEL.md §51). Earlier (0.16.124) — when a project declares `.conduit/demonstrate`, Bridge runs that bounded command at the delivered head and attaches a stamped `preview` row (KERNEL.md §47). Earlier (0.16.95) — Conduit-fuel lanes bind organization aliases (T144), the Anthropic base URL is the origin (T148), the investigation lane resolves its model (T154); a hosted container image lives under `hosted/` (docs/HOSTED_RUNNER.md). Earlier (0.16.27) — work-package execution budgets reach every agent turn, are bounded by the machine ceiling, and expose their effective source for operations. Local-fuel provider refusals make the affected lane unavailable instead of repeatedly spending attempts; an operator who changes the lane's account or plan can invalidate that observation with `ops quota-clear <driver>`. Bridge discovers bounded repository verification commands, including Make targets `test`, `check`, `verify`, `replay`, `typecheck`, `lint`, and `build`. `ops disconnect` asks before it removes the runner service and clears credentials; pass `--yes` to skip the question. `ops.env` is enrollment/bootstrap defaults only: an explicit workspace does not inherit an old repository, and project switches do not rewrite global project state. `ops enroll` exchanges a single-use token, registers the machine, binds project affinity, provisions fuel keys, brings detected drivers online, and starts the runner in one command. On Linux, `ops install` refuses any effective systemd drop-in. A switch intent remains queued until the target runner heartbeat proves Bound. After every Bridge publish, operators must re-run `ops install` (LaunchAgent pins an absolute `cli.js`).
6
6
 
7
7
  ## Prerequisites
8
8
 
package/dist/brief.js CHANGED
@@ -3,6 +3,7 @@ import { join } from "node:path";
3
3
  import { execFile } from "node:child_process";
4
4
  import { promisify } from "node:util";
5
5
  import { isBoundedVerificationCommand } from "./execution-class.js";
6
+ import { readDeclaredDemonstration } from "./ensure-demonstration-evidence.js";
6
7
  import { gitOriginUrl, headCommitOrNull } from "./git.js";
7
8
  const execFileAsync = promisify(execFile);
8
9
  const MANIFESTS = [
@@ -39,6 +40,7 @@ export async function buildWorkspaceBrief(workspace) {
39
40
  manifests,
40
41
  verification: await discoverVerificationCommands(workspace, files),
41
42
  declared_verification: declared,
43
+ declared_demonstration: await readDeclaredDemonstration(workspace),
42
44
  };
43
45
  }
44
46
  /**
@@ -0,0 +1,98 @@
1
+ /**
2
+ * When the project declares how it shows itself, Bridge runs that command at the delivered head and
3
+ * attaches what it printed. The agent never authors this entry (KERNEL.md §47, "See it").
4
+ *
5
+ * `.conduit/demonstrate` is one bounded command, `#` comments allowed, absent by default. It runs
6
+ * with the same shape check, runner and bound as a verification command, and it is never a gate:
7
+ * a demonstration that fails, times out or prints nothing attaches as `unverifiable` with its
8
+ * reason, and cannot fail a criterion.
9
+ */
10
+ import { readFile } from "node:fs/promises";
11
+ import { join } from "node:path";
12
+ import { runBoundedVerificationCommand } from "./ensure-test-evidence.js";
13
+ import { isRunnableVerificationCommand } from "./execution-class.js";
14
+ /** Fixed name the control plane reads to place the row on the decision card. */
15
+ export const DEMONSTRATION_ARTIFACT_NAME = "What it does (Bridge witness)";
16
+ export const DEMONSTRATION_DECLARATION_PATH = ".conduit/demonstrate";
17
+ /** The transcript is text the owner reads, not a log: the head, cut with a marker. */
18
+ export const DEMONSTRATION_MAX_CHARS = 4_000;
19
+ export function parseDeclaredDemonstration(text) {
20
+ for (const raw of text.split("\n")) {
21
+ const line = raw.split("#")[0].trim();
22
+ if (!line)
23
+ continue;
24
+ return isRunnableVerificationCommand(line) ? line : null;
25
+ }
26
+ return null;
27
+ }
28
+ export async function readDeclaredDemonstration(workspace) {
29
+ try {
30
+ return parseDeclaredDemonstration(await readFile(join(workspace, DEMONSTRATION_DECLARATION_PATH), "utf8"));
31
+ }
32
+ catch {
33
+ return null; // absent declaration, absent row
34
+ }
35
+ }
36
+ function boundedTranscript(text) {
37
+ const trimmed = text.trim();
38
+ const cut = trimmed.length > DEMONSTRATION_MAX_CHARS;
39
+ const kept = cut ? trimmed.slice(0, DEMONSTRATION_MAX_CHARS) : trimmed;
40
+ return [...kept.split("\n"), ...(cut ? [`… cut at ${DEMONSTRATION_MAX_CHARS.toLocaleString("en-US")} characters …`] : [])];
41
+ }
42
+ export async function ensureDemonstrationEvidence(input) {
43
+ const command = await readDeclaredDemonstration(input.workspace);
44
+ if (!command)
45
+ return input.report;
46
+ const run = input.runCommand ?? runBoundedVerificationCommand;
47
+ const withoutPrior = input.report.evidence.filter((item) => item.name !== DEMONSTRATION_ARTIFACT_NAME);
48
+ const attach = (details, witness, uri) => ({
49
+ ...input.report,
50
+ evidence: [...withoutPrior, {
51
+ kind: "preview",
52
+ name: DEMONSTRATION_ARTIFACT_NAME,
53
+ ...(uri ? { uri } : {}),
54
+ details: [`$ ${command}`, ...details],
55
+ acceptance_criteria: [],
56
+ witness,
57
+ }],
58
+ });
59
+ // A demonstration is repository code. Running it must consume the same explicit authority as a
60
+ // verification command; merely finding the declaration cannot grant shell execution to an
61
+ // observe-only package.
62
+ if (!input.grants.includes("test_run")) {
63
+ return attach(["Not run: this package does not hold test_run authority."], "unverifiable");
64
+ }
65
+ // The delivered code may demonstrate itself, but it may not author the command that earns the
66
+ // Bridge stamp in the same delivery. The declaration becomes a trusted project property only
67
+ // after an earlier delivery landed it. A missing path witness fails closed for the same reason.
68
+ if (input.changedPaths === null || input.changedPaths.includes(DEMONSTRATION_DECLARATION_PATH)) {
69
+ return attach([
70
+ `Not run: this delivery changed ${DEMONSTRATION_DECLARATION_PATH}; a delivery cannot author its own Bridge-witnessed demonstration.`,
71
+ ], "unverifiable");
72
+ }
73
+ let result;
74
+ try {
75
+ result = await run(command, input.workspace);
76
+ }
77
+ catch (error) {
78
+ return attach([`Could not run: ${error instanceof Error ? error.message : String(error)}`], "unverifiable");
79
+ }
80
+ if (result.code !== 0) {
81
+ return attach([...boundedTranscript(result.stderr || result.stdout), `exit ${result.code}`], "unverifiable");
82
+ }
83
+ if (!result.stdout.trim())
84
+ return attach(["The demonstration printed nothing."], "unverifiable");
85
+ const transcript = boundedTranscript(result.stdout);
86
+ // A line that is an https:// URL is the project publishing where to look; it becomes the preview reference.
87
+ const link = transcript.map((line) => line.trim()).find((line) => {
88
+ if (!line.startsWith("https://"))
89
+ return false;
90
+ try {
91
+ return new URL(line).protocol === "https:";
92
+ }
93
+ catch {
94
+ return false;
95
+ }
96
+ });
97
+ return attach(transcript, "bridge", link);
98
+ }
@@ -51,7 +51,7 @@ export async function ensureLandCommit(input) {
51
51
  if (!requiresLandCommit({ grants: input.grants, spec: input.spec })) {
52
52
  return { kind: "skipped" };
53
53
  }
54
- const base = input.spec.repository?.base_commit;
54
+ const base = input.baseCommit ?? input.spec.repository?.base_commit;
55
55
  if (!base)
56
56
  return { kind: "skipped" };
57
57
  const countAhead = input.countCommitsAhead ?? commitsAheadOfBase;
@@ -263,7 +263,7 @@ export async function ensureDeliveryPullRequest(input) {
263
263
  // files. GitHub then answers the pull-request call with an opaque 422 "No commits between main
264
264
  // and <branch>" (initiative efa56ccd, attempt 874fa0e3). Prove the branch carries work first, and
265
265
  // report the real condition instead of a forge validation error.
266
- const base = input.spec.repository?.base_commit;
266
+ const base = input.baseCommit ?? input.spec.repository?.base_commit;
267
267
  if (base) {
268
268
  const ahead = await countAhead(input.workspace, base);
269
269
  if (ahead === 0) {
package/dist/execution.js CHANGED
@@ -27,6 +27,7 @@ import { agentClaimsRepositoryWork, claimsVsGitMismatch, isLandTreeEmpty, report
27
27
  const execFileAsync = promisify(execFile);
28
28
  import { boundedTail, captureVerificationFailure, detectGateRanNothing, ensureTestEvidence, needsTestEvidence, runBoundedVerificationCommand, verificationEvidenceCommands, VerificationGateRanNothingError } from "./ensure-test-evidence.js";
29
29
  import { ensureChangeEvidence } from "./ensure-change-evidence.js";
30
+ import { ensureDemonstrationEvidence } from "./ensure-demonstration-evidence.js";
30
31
  import { ensureNormativeEvidence } from "./ensure-normative-evidence.js";
31
32
  import { changedPathsSince, compareWorktreeState, diffStatSince, worktreeStateFingerprint, worktreeWrittenPaths } from "./git-witness.js";
32
33
  import { assertNormativeRefsMaterialized, checkNormativeMarkers, materializeNormativeRefs, NORMATIVE_MARKER_PREFIX, NORMATIVE_REF_PREFIX, parseNormativeRefs, } from "./normative-refs.js";
@@ -1803,7 +1804,7 @@ async function runAttempt(client, config, driver, workspace, brief, taskId, watc
1803
1804
  watchdog.phase("land");
1804
1805
  if (requiresLandCommit({ grants, spec })) {
1805
1806
  try {
1806
- const land = await ensureLandCommit({ workspace: attemptWorkspace, spec, grants });
1807
+ const land = await ensureLandCommit({ workspace: attemptWorkspace, spec, grants, baseCommit: deliveryBaseCommit });
1807
1808
  if (land.kind === "committed") {
1808
1809
  await client.attemptRequest(taskId, "progress", {
1809
1810
  phase: "preparing_delivery",
@@ -1825,6 +1826,7 @@ async function runAttempt(client, config, driver, workspace, brief, taskId, watc
1825
1826
  spec,
1826
1827
  grants,
1827
1828
  agentReply: reportText,
1829
+ baseCommit: deliveryBaseCommit,
1828
1830
  })) {
1829
1831
  const continuation = await runLandContinuationTurn({
1830
1832
  config,
@@ -1859,7 +1861,7 @@ async function runAttempt(client, config, driver, workspace, brief, taskId, watc
1859
1861
  report = parseAgentReport(reportText, spec.acceptance ?? []);
1860
1862
  }
1861
1863
  catch (error) {
1862
- const gitEmpty = await isLandTreeEmpty({ workspace: attemptWorkspace, spec, grants });
1864
+ const gitEmpty = await isLandTreeEmpty({ workspace: attemptWorkspace, spec, grants, baseCommit: deliveryBaseCommit });
1863
1865
  const claimsWork = agentClaimsRepositoryWork(reportText);
1864
1866
  if (requiresLandCommit({ grants, spec }) && gitEmpty && claimsWork) {
1865
1867
  if (!landContinuationUsed) {
@@ -2059,7 +2061,7 @@ async function runAttempt(client, config, driver, workspace, brief, taskId, watc
2059
2061
  if (!landContinuationUsed
2060
2062
  && requiresLandCommit({ grants, spec })
2061
2063
  && reportClaimsRepositoryWork(report)
2062
- && await isLandTreeEmpty({ workspace: attemptWorkspace, spec, grants })) {
2064
+ && await isLandTreeEmpty({ workspace: attemptWorkspace, spec, grants, baseCommit: deliveryBaseCommit })) {
2063
2065
  const continuation = await runLandContinuationTurn({
2064
2066
  config,
2065
2067
  client,
@@ -2129,6 +2131,7 @@ async function runAttempt(client, config, driver, workspace, brief, taskId, watc
2129
2131
  maxDurationMs: workPackage?.max_duration_ms,
2130
2132
  resumeSessionId: agentSessionId,
2131
2133
  landContinuationUsed,
2134
+ landBaseCommit: deliveryBaseCommit,
2132
2135
  });
2133
2136
  // Mechanical land path: the agent only pushes; Bridge pushes again if needed and the control
2134
2137
  // plane opens the change request with the organization's forge connection.
@@ -2140,6 +2143,7 @@ async function runAttempt(client, config, driver, workspace, brief, taskId, watc
2140
2143
  report,
2141
2144
  spec,
2142
2145
  grants,
2146
+ baseCommit: deliveryBaseCommit,
2143
2147
  title: task.objective,
2144
2148
  repositoryFingerprint: executionContract.repository_fingerprint,
2145
2149
  priorPullRequestUrl: executionContract.prior_pull_request_url,
@@ -2166,6 +2170,16 @@ async function runAttempt(client, config, driver, workspace, brief, taskId, watc
2166
2170
  grants,
2167
2171
  changedPaths: actualPaths,
2168
2172
  });
2173
+ // §47 "See it": the project's own demonstration at the delivered head, never a gate.
2174
+ const beforeDemonstration = report;
2175
+ report = await ensureDemonstrationEvidence({
2176
+ workspace: attemptWorkspace,
2177
+ report,
2178
+ grants,
2179
+ changedPaths: actualPaths,
2180
+ });
2181
+ if (report !== beforeDemonstration)
2182
+ await discardWorktreeWrites(attemptWorkspace);
2169
2183
  const integrationCheck = await checkIntegrationObligations(attemptWorkspace, parseIntegrationObligations(spec.integration_obligations));
2170
2184
  if (!integrationCheck.ok) {
2171
2185
  throw new Error(`${INTEGRATION_OBLIGATION_PREFIX}: ${integrationCheck.failures.join("; ")}`);
@@ -2371,6 +2385,7 @@ async function finalizeRepositoryLand(input) {
2371
2385
  workspace: input.workspace,
2372
2386
  spec: input.spec,
2373
2387
  grants: input.grants,
2388
+ baseCommit: input.landBaseCommit,
2374
2389
  });
2375
2390
  if (land.kind === "committed") {
2376
2391
  await input.client.attemptRequest(input.taskId, "progress", {
@@ -2392,7 +2407,7 @@ async function finalizeRepositoryLand(input) {
2392
2407
  throw error;
2393
2408
  }
2394
2409
  if (input.landContinuationUsed) {
2395
- throw new AgentNoLandCommitError(input.spec.repository?.base_commit ?? "unknown");
2410
+ throw new AgentNoLandCommitError(input.landBaseCommit ?? input.spec.repository?.base_commit ?? "unknown");
2396
2411
  }
2397
2412
  const continuation = await runLandContinuationTurn({
2398
2413
  config: input.config,
@@ -2664,7 +2679,7 @@ async function prepareDelivery(client, attemptId, taskId, report) {
2664
2679
  metadata: {
2665
2680
  details: item.details,
2666
2681
  acceptance_criteria: item.acceptance_criteria,
2667
- ...(item.witness === "bridge" ? { witness: "bridge" } : {}),
2682
+ ...(item.witness ? { witness: item.witness } : {}),
2668
2683
  },
2669
2684
  idempotency_key: `bridge:artifact:${attemptId}:${index + 1}`,
2670
2685
  });
@@ -117,7 +117,7 @@ export const BRIDGE_CAUSES = {
117
117
  workspace_head_changed: { class: "environment", disposition: "hold", responsible_party: "computer_operator", message: "The checkout changed after Conduit prepared the assignment.", next_action: "Let the checkout settle, then recheck readiness." },
118
118
  base_not_ancestor: { class: "environment", disposition: "hold", responsible_party: "computer_operator", message: "Conduit could not prepare the required project version on this computer.", next_action: "No Git work is required from the product owner. Keep the computer and Bridge online, then try again so Bridge can refresh the project. If the hold returns, the computer operator should check Bridge's repository access." },
119
119
  workspace_dirty: { class: "environment", disposition: "hold", responsible_party: "computer_operator", message: "The source workspace has uncommitted changes.", next_action: "Commit, stash, or discard the local changes, then recheck readiness." },
120
- missing_verification: { class: "environment", disposition: "hold", responsible_party: "conduit", message: "This checkout has no verification commands Conduit can run for this package.", next_action: "Conductor will adjust how this package is verified. You do not need to author test commands or rewrite the plan for tooling." },
120
+ missing_verification: { class: "environment", disposition: "hold", responsible_party: "conduit", message: "This checkout has no verification commands Conduit can run for this package.", next_action: "Open the initiative and request a revision: Conduit re-plans this package without test evidence this checkout cannot produce. You never author test commands yourself." },
121
121
  verification_unwitnessable: { class: "environment", disposition: "hold", responsible_party: "computer_operator", message: "The project's verification command runs but prints nothing, so test evidence cannot be witnessed.", next_action: "Fix the verification recipe in the checkout so it prints real output, then recheck readiness. You do not need to author test commands for the agent." },
122
122
  execution_contract_failed: { class: "contract", disposition: "rework", responsible_party: "conduit", message: "The agent could not satisfy the approved execution contract.", next_action: "Review the last run and rework the same contract; change the plan only if its authority or outcome is wrong." },
123
123
  agent_no_land_commit: { class: "contract", disposition: "rework", responsible_party: "conduit", message: "The agent finished without committing the repository changes this package requires.", next_action: "Retry implement. Conductor will brief a land-focused recovery attempt — you do not need to edit technical constraints." },
@@ -790,18 +790,25 @@ export async function executeNextInvestigation(client, config, workspace, brief,
790
790
  : undefined;
791
791
  // T126: the prompt names the commands of the repository this lane opened — not the control
792
792
  // plane's idea of them — and carries the diff stat Bridge computed, since the lane cannot run git.
793
+ // Discover those commands from the delivered worktree, not the source checkout: a greenfield
794
+ // delivery can introduce its manifest and test gate in the commit this investigation verifies.
793
795
  const deliveryVerification = isDeliveryVerification(assignment);
796
+ const investigationBrief = deliveryVerification
797
+ ? await buildWorkspaceBrief(attemptWorkspace)
798
+ : liveBrief;
799
+ const verificationCommands = investigationBrief?.verification ?? [];
800
+ const declaredVerificationCommands = investigationBrief?.declared_verification ?? [];
794
801
  const gatesRun = deliveryVerification
795
802
  ? await runDeliveryVerificationGates({
796
803
  workspace: attemptWorkspace,
797
- verificationCommands: liveBrief?.verification ?? [],
798
- declaredVerificationCommands: liveBrief?.declared_verification ?? [],
804
+ verificationCommands,
805
+ declaredVerificationCommands,
799
806
  acceptance: assignment.acceptance ?? [],
800
807
  runCommand: options.runVerificationCommand,
801
808
  })
802
809
  : [];
803
810
  const context = {
804
- verificationCommands: liveBrief?.verification ?? [],
811
+ verificationCommands,
805
812
  diffStat: assignment.base_commit ? await diffStatSince(attemptWorkspace, assignment.base_commit) : null,
806
813
  gatesRun,
807
814
  };
@@ -815,7 +822,7 @@ export async function executeNextInvestigation(client, config, workspace, brief,
815
822
  workspace: attemptWorkspace,
816
823
  ...(selection.model ? { model: selection.model } : {}),
817
824
  grants: assignment.grants,
818
- verificationCommands: liveBrief?.verification ?? [],
825
+ verificationCommands,
819
826
  deliverable: "repository",
820
827
  // The same signal the read-only diagnosis lane uses; it is what denies edits in the driver.
821
828
  workRole: "diagnose",
@@ -33,7 +33,7 @@ async function listUncommittedPaths(workspace) {
33
33
  export async function isLandTreeEmpty(input) {
34
34
  if (!requiresLandCommit({ grants: input.grants, spec: input.spec }))
35
35
  return false;
36
- const base = input.spec.repository?.base_commit;
36
+ const base = input.baseCommit ?? input.spec.repository?.base_commit;
37
37
  if (!base)
38
38
  return false;
39
39
  const countAhead = input.countCommitsAhead ?? commitsAheadOfBase;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miraland-labs/conduit-bridge",
3
- "version": "0.16.121",
3
+ "version": "0.16.127",
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": {