@miraland-labs/conduit-bridge 0.16.23 → 0.16.24
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 +32 -7
- package/dist/execution-facts.js +127 -0
- package/dist/execution.js +32 -1
- package/dist/ops.js +4 -1
- package/dist/service.js +2 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -14,6 +14,7 @@ import { detectInstalledClients, localFuelOnlyClients, suggestFuelSource } from
|
|
|
14
14
|
import { DRIVERS } from "./driver.js";
|
|
15
15
|
import { driversHeartbeatReport, driverLabel, heartbeatStatusForDrivers, isSupportedDriverId, listDriverLanes, onlineDriverIds, seedDriversFromDetection, seedDriverLanes, setDriverFuel, setDriversOnline, } from "./drivers.js";
|
|
16
16
|
import { buildWorkspaceBrief } from "./brief.js";
|
|
17
|
+
import { BOOTSTRAP_RESULTS, buildSovereignExecutionFacts } from "./execution-facts.js";
|
|
17
18
|
import { ensureCheckout } from "./checkout.js";
|
|
18
19
|
import { buildOnShiftIntentProof, maybeApplyOnShiftIntent } from "./on-shift-apply.js";
|
|
19
20
|
import { loadOpsEnv, OPS_VERBS, runOps } from "./ops.js";
|
|
@@ -37,6 +38,12 @@ function parseFuelSource(value) {
|
|
|
37
38
|
return value;
|
|
38
39
|
throw new Error("Fuel source must be conduit or local");
|
|
39
40
|
}
|
|
41
|
+
function parseBootstrapResult(value) {
|
|
42
|
+
const result = BOOTSTRAP_RESULTS.find((candidate) => candidate === value);
|
|
43
|
+
if (!result)
|
|
44
|
+
throw new Error(`Bootstrap result must be one of: ${BOOTSTRAP_RESULTS.join(", ")}`);
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
40
47
|
async function connect() {
|
|
41
48
|
const { values } = parseArgs({ args: process.argv.slice(3), options: { url: { type: "string" }, code: { type: "string" }, fuel: { type: "string" } } });
|
|
42
49
|
if (!values.url || !values.code)
|
|
@@ -319,7 +326,7 @@ async function installService() {
|
|
|
319
326
|
let config = await loadConfig();
|
|
320
327
|
const { values } = parseArgs({ args: process.argv.slice(3), options: {
|
|
321
328
|
workspace: { type: "string" }, interval: { type: "string" }, "agent-timeout-minutes": { type: "string" },
|
|
322
|
-
"ensure-checkout": { type: "string" },
|
|
329
|
+
"ensure-checkout": { type: "string" }, "bootstrap-result": { type: "string" },
|
|
323
330
|
} });
|
|
324
331
|
if (!values.workspace) {
|
|
325
332
|
throw new Error(`Usage: ${bridgeUsage("install-service", "--workspace", "<repository-path>", "[--ensure-checkout <repository-url>]")} (workspace required; uses online driver lanes)`);
|
|
@@ -329,6 +336,9 @@ async function installService() {
|
|
|
329
336
|
throw new Error(`No online driver lanes. Run \`${bridgeUsage("drivers", "online", AGENT_PLACEHOLDER)}\` first.`);
|
|
330
337
|
}
|
|
331
338
|
const workspace = resolve(values.workspace);
|
|
339
|
+
const bootstrapResult = values["bootstrap-result"]
|
|
340
|
+
? parseBootstrapResult(values["bootstrap-result"])
|
|
341
|
+
: undefined;
|
|
332
342
|
if (values["ensure-checkout"]) {
|
|
333
343
|
const result = await ensureCheckout(workspace, values["ensure-checkout"]);
|
|
334
344
|
console.log(result === "cloned"
|
|
@@ -340,6 +350,7 @@ async function installService() {
|
|
|
340
350
|
interval: values.interval,
|
|
341
351
|
agentTimeoutMinutes: values["agent-timeout-minutes"],
|
|
342
352
|
ensureCheckout: values["ensure-checkout"],
|
|
353
|
+
bootstrapResult,
|
|
343
354
|
});
|
|
344
355
|
console.log(`Installed Conduit Bridge v${bridgeVersion()} (protocol ${BRIDGE_PROTOCOL_VERSION}) runner service (${result.platform}): ${result.path}`);
|
|
345
356
|
console.log(`Online lanes: ${onlineDriverIds(config).join(", ")}. Toggle with \`${bridgeUsage("drivers", "online|offline", "…")}\`.`);
|
|
@@ -466,9 +477,13 @@ async function runner() {
|
|
|
466
477
|
const { values } = parseArgs({ args: process.argv.slice(3), options: {
|
|
467
478
|
workspace: { type: "string" }, interval: { type: "string" }, once: { type: "boolean" },
|
|
468
479
|
"agent-timeout-minutes": { type: "string" }, fuel: { type: "string" }, "ensure-checkout": { type: "string" },
|
|
480
|
+
"bootstrap-result": { type: "string" },
|
|
469
481
|
} });
|
|
470
482
|
let config = await loadConfig();
|
|
471
483
|
const fuelOverride = parseFuelSource(values.fuel);
|
|
484
|
+
const bootstrapResult = values["bootstrap-result"]
|
|
485
|
+
? parseBootstrapResult(values["bootstrap-result"])
|
|
486
|
+
: undefined;
|
|
472
487
|
if (fuelOverride) {
|
|
473
488
|
config.fuelSource = fuelOverride;
|
|
474
489
|
await saveConfigPrefs(config);
|
|
@@ -511,7 +526,7 @@ async function runner() {
|
|
|
511
526
|
const preflight = workspace
|
|
512
527
|
? await cachedBridgePreflight({ config, workspace, brief: currentBrief ?? undefined })
|
|
513
528
|
: unavailableWorkspacePreflight({ config });
|
|
514
|
-
const hb = await heartbeat(client, config, workspace, currentBrief, preflight);
|
|
529
|
+
const hb = await heartbeat(client, config, workspace, currentBrief, preflight, undefined, bootstrapResult);
|
|
515
530
|
if (hb.staleBridge) {
|
|
516
531
|
console.error(`Bridge update required: running protocol ${BRIDGE_PROTOCOL_VERSION}; control plane requires protocol ${hb.requiredProtocol ?? "unknown"} (minimum Bridge ${hb.minimumVersion ?? "unknown"}). Reinstall the latest Bridge, then restart this runner.`);
|
|
517
532
|
await new Promise((resolveSleep) => setTimeout(resolveSleep, Math.max(intervalMs, 60_000)));
|
|
@@ -548,7 +563,7 @@ async function runner() {
|
|
|
548
563
|
}
|
|
549
564
|
const intentProof = buildOnShiftIntentProof({ currentWorkspace: workspace, onShift: hb.on_shift });
|
|
550
565
|
if (intentProof) {
|
|
551
|
-
await heartbeat(client, config, workspace, currentBrief, preflight, intentProof);
|
|
566
|
+
await heartbeat(client, config, workspace, currentBrief, preflight, intentProof, bootstrapResult);
|
|
552
567
|
}
|
|
553
568
|
await renewLeases(client, config);
|
|
554
569
|
if (workspace && onlineDriverIds(config).length) {
|
|
@@ -561,7 +576,7 @@ async function runner() {
|
|
|
561
576
|
heartbeat: async () => {
|
|
562
577
|
const currentBrief = await buildWorkspaceBrief(workspace).catch(() => brief);
|
|
563
578
|
const preflight = await cachedBridgePreflight({ config, workspace, brief: currentBrief ?? undefined });
|
|
564
|
-
await heartbeat(client, config, workspace, currentBrief, preflight);
|
|
579
|
+
await heartbeat(client, config, workspace, currentBrief, preflight, undefined, bootstrapResult);
|
|
565
580
|
},
|
|
566
581
|
beforeClaim: async (driverId) => {
|
|
567
582
|
// Never let the five-minute heartbeat cache span a CLI upgrade into a certified claim.
|
|
@@ -569,7 +584,7 @@ async function runner() {
|
|
|
569
584
|
// exact version frozen onto the claim response and event.
|
|
570
585
|
const currentBrief = await buildWorkspaceBrief(workspace).catch(() => brief);
|
|
571
586
|
const preflight = await cachedBridgePreflight({ config, workspace, brief: currentBrief ?? undefined }, { force: true });
|
|
572
|
-
const hb = await heartbeat(client, config, workspace, currentBrief, preflight);
|
|
587
|
+
const hb = await heartbeat(client, config, workspace, currentBrief, preflight, undefined, bootstrapResult);
|
|
573
588
|
if (hb.staleBridge)
|
|
574
589
|
return false;
|
|
575
590
|
const lane = preflight.drivers.find((candidate) => candidate.id === driverId);
|
|
@@ -590,19 +605,29 @@ async function runner() {
|
|
|
590
605
|
await new Promise((resolveSleep) => setTimeout(resolveSleep, intervalMs));
|
|
591
606
|
}
|
|
592
607
|
}
|
|
593
|
-
async function heartbeat(client, config, workspacePath, brief, preflight, intentProof) {
|
|
608
|
+
async function heartbeat(client, config, workspacePath, brief, preflight, intentProof, bootstrapResult) {
|
|
594
609
|
const online = onlineDriverIds(config);
|
|
595
610
|
const status = heartbeatStatusForDrivers(online);
|
|
611
|
+
const version = bridgeVersion();
|
|
612
|
+
const executionFacts = await buildSovereignExecutionFacts({
|
|
613
|
+
workspace: workspacePath,
|
|
614
|
+
brief,
|
|
615
|
+
workspaceClean: preflight.workspace_clean,
|
|
616
|
+
bridgeVersion: version,
|
|
617
|
+
bridgeProtocol: BRIDGE_PROTOCOL_VERSION,
|
|
618
|
+
bootstrapResult,
|
|
619
|
+
});
|
|
596
620
|
const response = await client.request("/runner/v1/heartbeat", { method: "POST", body: JSON.stringify({
|
|
597
621
|
status,
|
|
598
622
|
capabilities: config.capabilities,
|
|
599
623
|
lease_capacity: config.leaseCapacity,
|
|
600
624
|
workspace_path: workspacePath,
|
|
601
625
|
fuel_source: config.fuelSource === "local" ? "local" : "conduit",
|
|
602
|
-
bridge_version:
|
|
626
|
+
bridge_version: version,
|
|
603
627
|
bridge_protocol: BRIDGE_PROTOCOL_VERSION,
|
|
604
628
|
drivers: driversHeartbeatReport(config, config.activeAttempts),
|
|
605
629
|
preflight,
|
|
630
|
+
execution_facts: executionFacts,
|
|
606
631
|
...(intentProof ? { on_shift_intent_proof: intentProof } : {}),
|
|
607
632
|
...(brief ? { workspace_brief: brief } : {}),
|
|
608
633
|
}) });
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { access, readFile, stat } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { execFile } from "node:child_process";
|
|
5
|
+
import { promisify } from "node:util";
|
|
6
|
+
import { normalizeRepositoryUrl } from "./brief.js";
|
|
7
|
+
const execFileAsync = promisify(execFile);
|
|
8
|
+
export const EXECUTION_CLASSES = ["observe", "observe_network", "publish_artifact", "verify", "mutate_repo"];
|
|
9
|
+
export const BOOTSTRAP_RESULTS = ["not_applicable", "not_run", "installed", "failed"];
|
|
10
|
+
/**
|
|
11
|
+
* Lockfiles are hashed, never uploaded. The set is intentionally explicit and root-scoped so a
|
|
12
|
+
* dependency change becomes a durable identity without moving repository contents onto Conduit.
|
|
13
|
+
*/
|
|
14
|
+
const LOCKFILE_NAMES = [
|
|
15
|
+
"package-lock.json", "npm-shrinkwrap.json", "yarn.lock", "pnpm-lock.yaml",
|
|
16
|
+
"Cargo.lock", "poetry.lock", "Pipfile.lock", "go.sum", "Gemfile.lock", "composer.lock",
|
|
17
|
+
];
|
|
18
|
+
/** Stable identity for the exact bounded verification command list used by Bridge. */
|
|
19
|
+
export function verificationCommandsDigest(commands) {
|
|
20
|
+
const normalized = [...new Set(commands.map((command) => command.trim()).filter(Boolean))];
|
|
21
|
+
if (!normalized.length)
|
|
22
|
+
return null;
|
|
23
|
+
return createHash("sha256").update(JSON.stringify(normalized)).digest("hex");
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Hash the root lockfiles in deterministic name order. Missing or unreadable lockfiles are simply
|
|
27
|
+
* absent from the identity; a workspace with no readable lockfile reports null rather than an
|
|
28
|
+
* invented digest.
|
|
29
|
+
*/
|
|
30
|
+
export async function lockfileDigest(workspace) {
|
|
31
|
+
const hash = createHash("sha256");
|
|
32
|
+
let found = false;
|
|
33
|
+
for (const name of LOCKFILE_NAMES) {
|
|
34
|
+
try {
|
|
35
|
+
const contents = await readFile(join(workspace, name));
|
|
36
|
+
hash.update(name);
|
|
37
|
+
hash.update("\0");
|
|
38
|
+
hash.update(contents);
|
|
39
|
+
hash.update("\0");
|
|
40
|
+
found = true;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// A missing or unreadable optional lockfile contributes no claim.
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return found ? hash.digest("hex") : null;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Report whether a JavaScript workspace has dependencies installed. This is an observed state, not
|
|
50
|
+
* a promise that Bridge will run a package manager during execution. Managed installs already run
|
|
51
|
+
* `npm ci` before the service is advertised, so a present node_modules directory is the durable
|
|
52
|
+
* local evidence available on later heartbeats.
|
|
53
|
+
*/
|
|
54
|
+
export async function bootstrapResultForWorkspace(workspace) {
|
|
55
|
+
if (!workspace)
|
|
56
|
+
return "not_applicable";
|
|
57
|
+
try {
|
|
58
|
+
await access(join(workspace, "package.json"));
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return "not_applicable";
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
const lockfile = await Promise.any(LOCKFILE_NAMES.map(async (name) => {
|
|
65
|
+
await access(join(workspace, name));
|
|
66
|
+
return true;
|
|
67
|
+
}));
|
|
68
|
+
void lockfile;
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return "not_run";
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
const dependencies = await stat(join(workspace, "node_modules"));
|
|
75
|
+
return dependencies.isDirectory() ? "installed" : "not_run";
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return "not_run";
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/** Read the source/attempt tree's Git cleanliness without returning its contents. */
|
|
82
|
+
export async function workspaceIsClean(workspace) {
|
|
83
|
+
try {
|
|
84
|
+
const result = await execFileAsync("git", ["-C", workspace, "status", "--porcelain", "--untracked-files=normal"], {
|
|
85
|
+
timeout: 15_000,
|
|
86
|
+
windowsHide: true,
|
|
87
|
+
});
|
|
88
|
+
return result.stdout.trim().length === 0;
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/** Read only the bounded HEAD identity retained when an attempt terminates. */
|
|
95
|
+
export async function finalCommitForWorkspace(workspace) {
|
|
96
|
+
try {
|
|
97
|
+
const result = await execFileAsync("git", ["-C", workspace, "rev-parse", "HEAD"], {
|
|
98
|
+
timeout: 15_000,
|
|
99
|
+
windowsHide: true,
|
|
100
|
+
});
|
|
101
|
+
return commitOrNull(result.stdout.trim());
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function commitOrNull(value) {
|
|
108
|
+
return value && /^[0-9a-f]{40,64}$/i.test(value) ? value.toLowerCase() : null;
|
|
109
|
+
}
|
|
110
|
+
/** Build one self-contained heartbeat/attempt snapshot from existing Bridge observations. */
|
|
111
|
+
export async function buildSovereignExecutionFacts(input) {
|
|
112
|
+
const repository = input.brief?.repository?.trim();
|
|
113
|
+
return {
|
|
114
|
+
os: process.platform,
|
|
115
|
+
architecture: process.arch,
|
|
116
|
+
repository_fingerprint: repository ? normalizeRepositoryUrl(repository) : null,
|
|
117
|
+
claimed_head: commitOrNull(input.claimedHead ?? input.brief?.base_commit),
|
|
118
|
+
lockfile_digest: input.workspace ? await lockfileDigest(input.workspace) : null,
|
|
119
|
+
bootstrap_result: input.bootstrapResult ?? await bootstrapResultForWorkspace(input.workspace),
|
|
120
|
+
bridge_version: input.bridgeVersion,
|
|
121
|
+
bridge_protocol: input.bridgeProtocol,
|
|
122
|
+
execution_class: input.executionClass ?? null,
|
|
123
|
+
verification_commands_digest: verificationCommandsDigest(input.brief?.verification ?? []),
|
|
124
|
+
workspace_clean: input.workspaceClean,
|
|
125
|
+
final_commit: commitOrNull(input.finalCommit),
|
|
126
|
+
};
|
|
127
|
+
}
|
package/dist/execution.js
CHANGED
|
@@ -10,6 +10,9 @@ import { attemptWorktreePath, createAttemptWorktree, proveResumeWorktree, quaran
|
|
|
10
10
|
import { execFile } from "node:child_process";
|
|
11
11
|
import { promisify } from "node:util";
|
|
12
12
|
import { buildWorkspaceBrief, ensureCommitAvailable, normalizeRepositoryUrl, resolveAttemptStartCommit } from "./brief.js";
|
|
13
|
+
import { buildSovereignExecutionFacts, bootstrapResultForWorkspace, finalCommitForWorkspace, workspaceIsClean } from "./execution-facts.js";
|
|
14
|
+
import { BRIDGE_PROTOCOL_VERSION } from "./preflight.js";
|
|
15
|
+
import { bridgeVersion } from "./version.js";
|
|
13
16
|
import { ensureDeliveryPullRequest } from "./ensure-pull-request.js";
|
|
14
17
|
import { ensureLandCommit } from "./ensure-land-commit.js";
|
|
15
18
|
import { AgentNoLandCommitError, agentNoLandCommitMessage, requiresLandCommit } from "./land-contract.js";
|
|
@@ -907,8 +910,20 @@ async function runClaimedAssignment(client, config, driver, workspace, brief, ta
|
|
|
907
910
|
normativeRefs: normativeMaterialized,
|
|
908
911
|
});
|
|
909
912
|
const resuming = Boolean(options.forceResumeSessionId);
|
|
913
|
+
const executionFacts = await buildSovereignExecutionFacts({
|
|
914
|
+
workspace: attemptWorkspace,
|
|
915
|
+
brief: attemptBrief,
|
|
916
|
+
workspaceClean: await workspaceIsClean(workspace),
|
|
917
|
+
bridgeVersion: bridgeVersion(),
|
|
918
|
+
bridgeProtocol: BRIDGE_PROTOCOL_VERSION,
|
|
919
|
+
executionClass,
|
|
920
|
+
claimedHead: executionContract.claimed_head ?? startCommit,
|
|
921
|
+
bootstrapResult: await bootstrapResultForWorkspace(workspace),
|
|
922
|
+
});
|
|
923
|
+
await client.updateAttempt(taskId, { executionFacts });
|
|
910
924
|
await client.attemptRequest(taskId, "progress", {
|
|
911
925
|
phase: diagnosis ? "inspecting" : "changing",
|
|
926
|
+
execution_facts: executionFacts,
|
|
912
927
|
message: resuming
|
|
913
928
|
? `Resuming ${driver.name} after Bridge restart with proven session and worktree.`
|
|
914
929
|
: diagnosis
|
|
@@ -1595,6 +1610,10 @@ async function submitFinishedDelivery(client, taskId) {
|
|
|
1595
1610
|
const active = client.attempt(taskId);
|
|
1596
1611
|
if (!active.delivery)
|
|
1597
1612
|
throw new Error("Finished agent run is missing its persisted Delivery data");
|
|
1613
|
+
const finalCommit = active.delivery.report.head_commit?.toLowerCase() ?? null;
|
|
1614
|
+
if (finalCommit && active.executionFacts) {
|
|
1615
|
+
await client.updateAttempt(taskId, { executionFacts: { ...active.executionFacts, final_commit: finalCommit } });
|
|
1616
|
+
}
|
|
1598
1617
|
const terminal = await prepareDelivery(client, active.attemptId, taskId, active.delivery.report);
|
|
1599
1618
|
await client.attemptRequest(taskId, "progress", { phase: "preparing_delivery", message: "Agent finished; submitting the Delivery.", idempotency_key: `bridge:progress:${active.attemptId}:delivery` });
|
|
1600
1619
|
return queueTerminal(client, taskId, terminal);
|
|
@@ -1870,7 +1889,19 @@ function retainDiagnosticWorktree(response) {
|
|
|
1870
1889
|
return response.retain_worktree === true || response.status === "invalid_lease";
|
|
1871
1890
|
}
|
|
1872
1891
|
async function queueTerminal(client, taskId, terminal) {
|
|
1873
|
-
|
|
1892
|
+
const active = client.attempt(taskId);
|
|
1893
|
+
let executionFacts = active.executionFacts;
|
|
1894
|
+
if (executionFacts && executionFacts.final_commit === null && active.worktreePath) {
|
|
1895
|
+
const finalCommit = await finalCommitForWorkspace(active.worktreePath);
|
|
1896
|
+
if (finalCommit) {
|
|
1897
|
+
executionFacts = { ...executionFacts, final_commit: finalCommit };
|
|
1898
|
+
await client.updateAttempt(taskId, { executionFacts });
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
const body = executionFacts && !terminal.body.execution_facts
|
|
1902
|
+
? { ...terminal.body, execution_facts: executionFacts }
|
|
1903
|
+
: terminal.body;
|
|
1904
|
+
await client.updateAttempt(taskId, { phase: "terminal_pending", terminal: { ...terminal, body } });
|
|
1874
1905
|
return flushTerminal(client, taskId);
|
|
1875
1906
|
}
|
|
1876
1907
|
export async function flushTerminal(client, taskId) {
|
package/dist/ops.js
CHANGED
|
@@ -570,6 +570,7 @@ export async function runOps(verb, argv = [], deps = {}) {
|
|
|
570
570
|
}
|
|
571
571
|
const workspace = resolve(expandOpsValue(installEnv.CONDUIT_WORKSPACE));
|
|
572
572
|
const drivers = await (deps.resolveInstallDrivers ?? resolveInstallDrivers)(installEnv, installArgv);
|
|
573
|
+
let bootstrapResult;
|
|
573
574
|
if (installEnv.CONDUIT_REPO) {
|
|
574
575
|
const checkout = deps.ensureCheckout ?? ensureCheckout;
|
|
575
576
|
const result = await checkout(workspace, installEnv.CONDUIT_REPO);
|
|
@@ -587,7 +588,7 @@ export async function runOps(verb, argv = [], deps = {}) {
|
|
|
587
588
|
&& !isAbsolute(managedRelative));
|
|
588
589
|
if (managedCheckout) {
|
|
589
590
|
const bootstrap = deps.bootstrapWorkspace ?? bootstrapManagedWorkspace;
|
|
590
|
-
|
|
591
|
+
bootstrapResult = bootstrap(workspace);
|
|
591
592
|
if (bootstrapResult === "installed")
|
|
592
593
|
console.log(`Installed locked project dependencies in ${workspace}`);
|
|
593
594
|
}
|
|
@@ -616,6 +617,8 @@ export async function runOps(verb, argv = [], deps = {}) {
|
|
|
616
617
|
const installArgs = ["install-service", "--workspace", workspace];
|
|
617
618
|
if (installEnv.CONDUIT_REPO)
|
|
618
619
|
installArgs.push("--ensure-checkout", installEnv.CONDUIT_REPO);
|
|
620
|
+
if (bootstrapResult)
|
|
621
|
+
installArgs.push("--bootstrap-result", bootstrapResult);
|
|
619
622
|
console.log(`Bridge: v${bridgeVersion()} (protocol ${BRIDGE_PROTOCOL_VERSION})`);
|
|
620
623
|
console.log(`Installing runner for ${workspace} (drivers: ${drivers.join(", ")})`);
|
|
621
624
|
runBridge(installArgs);
|
package/dist/service.js
CHANGED
|
@@ -30,6 +30,8 @@ export function runnerProgramArguments(options = {}) {
|
|
|
30
30
|
args.push("--interval", options.interval);
|
|
31
31
|
if (options.agentTimeoutMinutes)
|
|
32
32
|
args.push("--agent-timeout-minutes", options.agentTimeoutMinutes);
|
|
33
|
+
if (options.bootstrapResult)
|
|
34
|
+
args.push("--bootstrap-result", options.bootstrapResult);
|
|
33
35
|
return args;
|
|
34
36
|
}
|
|
35
37
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@miraland-labs/conduit-bridge",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.24",
|
|
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": {
|